use super::*;
#[cfg(feature = "presets")]
pub use presets::*;
#[doc(hidden)]
#[cfg(feature = "presets")]
mod presets {
use super::*;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum ServicePresetRef {
PresetId(String),
Preset(Box<DockerServicePreset>),
}
impl ServicePresetRef {
pub fn as_config(self) -> Option<Service> {
match self {
Self::PresetId(_) => None,
Self::Preset(docker_service_preset) => Some(docker_service_preset.config),
}
}
#[doc(hidden)]
pub fn requires_processing(&self) -> bool {
match self {
Self::PresetId(_) => true,
Self::Preset(data) => !data.extends_presets.is_empty(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, Merge)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
pub struct DockerServicePreset {
#[serde(skip_serializing)]
#[merge(skip)]
pub extends_presets: IndexSet<String>,
#[serde(flatten)]
pub config: Service,
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default, Merge)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
pub struct Service {
#[serde(skip_serializing_if = "Option::is_none")]
pub extends: Option<Extends>,
#[serde(skip_serializing_if = "Option::is_none")]
pub container_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hostname: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "build")]
#[merge(with = merge_options)]
pub build_: Option<BuildStep>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub depends_on: Option<DependsOn>,
#[serde(skip_serializing_if = "Option::is_none")]
pub command: Option<StringOrList>,
#[serde(skip_serializing_if = "Option::is_none")]
pub entrypoint: Option<StringOrList>,
#[serde(skip_serializing_if = "Option::is_none")]
pub healthcheck: Option<Healthcheck>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub expose: BTreeSet<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub env_file: Option<Envfile>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub environment: ListOrMap,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub annotations: ListOrMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub attach: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub blkio_config: Option<BlkioSettings>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub cap_add: BTreeSet<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub cap_drop: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cgroup: Option<Cgroup>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cgroup_parent: Option<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub configs: BTreeSet<ServiceConfigOrSecret>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_count: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_percent: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_period: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_quota: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_shares: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_rt_period: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpu_rt_runtime: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpus: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cpuset: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub credential_spec: Option<CredentialSpec>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deploy: Option<Deploy>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub develop: Option<DevelopmentSettings>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub device_cgroup_rules: BTreeSet<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub devices: BTreeSet<DeviceMapping>,
#[serde(default, skip_serializing_if = "StringOrSortedList::is_empty")]
pub dns: StringOrSortedList,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub dns_opt: BTreeSet<String>,
#[serde(default, skip_serializing_if = "StringOrSortedList::is_empty")]
pub dns_search: StringOrSortedList,
#[serde(skip_serializing_if = "Option::is_none")]
pub domainname: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub driver_opts: BTreeMap<String, StringOrNum>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub external_links: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub extra_hosts: Option<ExtraHosts>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub gpus: Option<Gpus>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub group_add: BTreeSet<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub init: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ipc: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub isolation: Option<String>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub labels: ListOrMap,
#[serde(default, skip_serializing_if = "StringOrSortedList::is_empty")]
pub label_file: StringOrSortedList,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub links: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logging: Option<LoggingSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mac_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mem_limit: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mem_reservation: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mem_swappiness: Option<u8>,
#[serde(skip_serializing_if = "Option::is_none")]
pub memswap_limit: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub models: Option<ServiceModels>,
#[serde(skip_serializing_if = "Option::is_none")]
pub network_mode: Option<NetworkMode>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub networks: Option<ServiceNetworks>,
#[serde(skip_serializing_if = "Option::is_none")]
pub oom_kill_disable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub oom_score_adj: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pids_limit: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub platform: Option<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub ports: BTreeSet<Port>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub post_start: Vec<ServiceHook>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub pre_stop: Vec<ServiceHook>,
#[serde(skip_serializing_if = "Option::is_none")]
pub privileged: Option<bool>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub profiles: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<Provider>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pull_policy: Option<PullPolicy>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pull_refresh_after: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub read_only: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub restart: Option<Restart>,
#[serde(skip_serializing_if = "Option::is_none")]
pub runtime: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scale: Option<u64>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub secrets: BTreeSet<ServiceConfigOrSecret>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub security_opt: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shm_size: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stdin_open: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_grace_period: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop_signal: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub storage_opt: BTreeMap<String, Value>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub sysctls: ListOrMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub tmpfs: Option<StringOrList>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tty: Option<bool>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub ulimits: BTreeMap<String, Ulimit>,
#[serde(skip_serializing_if = "Option::is_none")]
pub use_api_socket: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub userns_mode: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub uts: Option<Uts>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub volumes: Vec<ServiceVolume>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub volumes_from: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub working_dir: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum Extends {
Simple(String),
Detailed {
service: String,
#[serde(default)]
file: Option<String>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum Gpus {
#[serde(rename = "all")]
All,
#[serde(untagged)]
List(BTreeSet<GpuSettings>),
}
impl Merge for Gpus {
fn merge(&mut self, other: Self) {
match self {
Self::All => {}
Self::List(left_gpus) => match other {
Self::All => *self = Self::All,
Self::List(right_gpus) => left_gpus.extend(right_gpus),
},
}
}
}
#[derive(Clone, Debug, Serialize, Default, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct GpuSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub capabilities: Option<BTreeSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub count: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_ids: Option<BTreeSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub driver: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<ListOrMap>,
}
impl PartialOrd for GpuSettings {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for GpuSettings {
fn cmp(&self, other: &Self) -> Ordering {
self.driver
.cmp(&other.driver)
.then_with(|| self.count.cmp(&other.count))
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum ServiceModels {
List(BTreeSet<String>),
Map(BTreeMap<String, ServiceModelSettings>),
}
impl Merge for ServiceModels {
fn merge(&mut self, other: Self) {
if let Self::List(left_list) = self
&& let Self::List(right_list) = other
{
left_list.extend(right_list);
} else if let Self::Map(left_list) = self
&& let Self::Map(right_list) = other
{
left_list.extend(right_list);
} else {
*self = other;
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct ServiceModelSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub model_var: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub endpoint_var: Option<String>,
}
impl PartialOrd for ServiceModelSettings {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ServiceModelSettings {
fn cmp(&self, other: &Self) -> Ordering {
self.model_var.cmp(&other.model_var)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum NetworkMode {
Bridge,
Host,
None,
#[serde(untagged)]
Other(String),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum ServiceNetworks {
List(BTreeSet<String>),
Map(BTreeMap<String, ServiceNetworkSettings>),
}
impl ServiceNetworks {
pub fn contains(&self, key: &str) -> bool {
match self {
Self::List(list) => list.contains(key),
Self::Map(map) => map.contains_key(key),
}
}
}
impl Merge for ServiceNetworks {
fn merge(&mut self, other: Self) {
if let Self::List(left_list) = self
&& let Self::List(right_list) = other
{
left_list.extend(right_list);
} else if let Self::Map(left_list) = self
&& let Self::Map(right_list) = other
{
left_list.extend(right_list);
} else {
*self = other;
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct ServiceNetworkSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub interface_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub aliases: Option<BTreeSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ipv4_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ipv6_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mac_address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub gw_priority: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub link_local_ips: Option<BTreeSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub driver_opts: Option<BTreeMap<String, SingleValue>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum ProviderOptions {
Single(SingleValue),
List(Vec<SingleValue>),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub struct Provider {
#[serde(rename = "type")]
pub type_: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub options: Option<BTreeMap<String, ProviderOptions>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum Restart {
Always,
No,
OnFailure,
UnlessStopped,
#[serde(untagged)]
Other(String),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum BuildStep {
Simple(String),
Advanced(Box<AdvancedBuildStep>),
}
impl Merge for BuildStep {
fn merge(&mut self, other: Self) {
if let Self::Advanced(left_data) = self
&& let Self::Advanced(right_data) = other
{
left_data.merge(right_data);
} else {
*self = other;
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq, Default, Merge)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct AdvancedBuildStep {
#[serde(skip_serializing_if = "Option::is_none")]
pub context: Option<String>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub additional_contexts: ListOrMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub dockerfile: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dockerfile_inline: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub args: Option<ListOrMap>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub cache_from: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub cache_to: Vec<String>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub entitlements: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[merge(with = merge_options)]
pub extra_hosts: Option<ExtraHosts>,
#[serde(skip_serializing_if = "Option::is_none")]
pub isolation: Option<String>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub labels: ListOrMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub network: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_cache: Option<bool>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub platforms: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub privileged: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provenance: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pull: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sbom: Option<bool>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub secrets: BTreeSet<ServiceConfigOrSecret>,
#[serde(default, skip_serializing_if = "ListOrMap::is_empty")]
pub ssh: ListOrMap,
#[serde(skip_serializing_if = "Option::is_none")]
pub shm_size: Option<StringOrNum>,
#[serde(default, skip_serializing_if = "BTreeSet::is_empty")]
pub tags: BTreeSet<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<String>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub ulimits: BTreeMap<String, Ulimit>,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename = "kebab-case")]
pub enum Uts {
Host,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum DependsOn {
Simple(Vec<String>),
Conditional(IndexMap<String, DependsOnSettings>),
}
impl Merge for DependsOn {
fn merge(&mut self, other: Self) {
if let Self::Simple(left_list) = self
&& let Self::Simple(right_list) = other
{
left_list.extend(right_list);
} else if let Self::Conditional(left_list) = self
&& let Self::Conditional(right_list) = other
{
left_list.extend(right_list);
} else {
*self = other;
}
}
}
impl Default for DependsOn {
fn default() -> Self {
Self::Simple(Default::default())
}
}
impl DependsOn {
pub fn is_empty(&self) -> bool {
match self {
Self::Simple(v) => v.is_empty(),
Self::Conditional(m) => m.is_empty(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum DependsOnCondition {
ServiceCompletedSuccessfully,
ServiceHealthy,
ServiceStarted,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DependsOnSettings {
pub condition: DependsOnCondition,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub restart: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub required: Option<bool>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub driver: Option<LoggingDriver>,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<BTreeMap<String, Option<StringOrNum>>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum LoggingDriver {
Local,
JsonFile,
Syslog,
Journald,
Gelf,
Fluentd,
Awslogs,
Splunk,
Etwlogs,
Gcplogs,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct Healthcheck {
#[serde(skip_serializing_if = "Option::is_none")]
pub disable: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test: Option<StringOrList>,
#[serde(skip_serializing_if = "Option::is_none")]
pub interval: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_period: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_interval: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub retries: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum Envfile {
Simple(String),
List(Vec<EnvfileFormat>),
}
impl Merge for Envfile {
fn merge(&mut self, other: Self) {
match self {
Self::Simple(_) => {
*self = other;
}
Self::List(list) => match other {
Self::Simple(file) => list.push(EnvfileFormat::Simple(file)),
Self::List(files) => list.extend(files),
},
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum EnvfileFormat {
Simple(String),
Detailed(EnvFileDetailed),
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct EnvFileDetailed {
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub required: Option<bool>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct BlkioSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub device_read_bps: Option<BTreeSet<BlkioLimit>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_read_iops: Option<BTreeSet<BlkioLimit>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_write_bps: Option<BTreeSet<BlkioLimit>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_write_iops: Option<BTreeSet<BlkioLimit>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub weight: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub weight_device: Option<BTreeSet<BlkioWeight>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct BlkioLimit {
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rate: Option<StringOrNum>,
}
impl PartialOrd for BlkioLimit {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for BlkioLimit {
fn cmp(&self, other: &Self) -> Ordering {
self.path
.cmp(&other.path)
.then_with(|| self.rate.cmp(&other.rate))
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct BlkioWeight {
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub weight: Option<StringOrNum>,
}
impl PartialOrd for BlkioWeight {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for BlkioWeight {
fn cmp(&self, other: &Self) -> Ordering {
self.path
.cmp(&other.path)
.then_with(|| self.weight.cmp(&other.weight))
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum Cgroup {
Host,
Private,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct CredentialSpec {
#[serde(skip_serializing_if = "Option::is_none")]
pub config: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub file: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub registry: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Default, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DevelopmentSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub watch: Option<BTreeSet<WatchItem>>,
}
impl Merge for DevelopmentSettings {
fn merge(&mut self, other: Self) {
merge_options(&mut self.watch, other.watch);
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct WatchItem {
pub action: WatchAction,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub exec: Option<ServiceHook>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub ignore: Option<BTreeSet<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub include: Option<BTreeSet<String>>,
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub target: Option<String>,
}
impl PartialOrd for WatchItem {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for WatchItem {
fn cmp(&self, other: &Self) -> Ordering {
self.action.cmp(&other.action)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "kebab-case")]
pub enum WatchAction {
Rebuild,
Restart,
Sync,
#[serde(rename = "sync+restart")]
SyncRestart,
#[serde(rename = "sync+exec")]
SyncExec,
}
#[derive(Clone, Debug, Serialize, Default, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct ServiceHook {
#[serde(skip_serializing_if = "Option::is_none")]
pub privileged: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub working_dir: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub environment: Option<ListOrMap>,
#[serde(skip_serializing_if = "Option::is_none")]
pub command: Option<StringOrList>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum DeviceMapping {
String(String),
Detailed(DeviceMappingSettings),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DeviceMappingSettings {
pub source: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub target: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub permissions: Option<String>,
}
impl PartialOrd for DeviceMappingSettings {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for DeviceMappingSettings {
fn cmp(&self, other: &Self) -> Ordering {
self.source.cmp(&other.source)
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum ServiceVolume {
Simple(String),
Advanced(ServiceVolumeSettings),
}
impl PartialOrd for ServiceVolume {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ServiceVolume {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self {
Self::Simple(s) => match other {
Self::Simple(other_s) => s.cmp(other_s),
Self::Advanced(_) => Ordering::Greater,
},
Self::Advanced(v) => match other {
Self::Simple(_) => Ordering::Less,
Self::Advanced(other_v) => v.type_.cmp(&other_v.type_),
},
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum VolumeType {
Bind,
Cluster,
Npipe,
Image,
Tmpfs,
Volume,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct ServiceVolumeSettings {
#[serde(rename = "type")]
pub type_: VolumeType,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub read_only: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub source: Option<String>,
pub target: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub consistency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub bind: Option<Bind>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub image: Option<ImageVolumeSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub tmpfs: Option<TmpfsSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default)]
pub volume: Option<VolumeSettings>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum Propagation {
Private,
Rprivate,
Rshared,
Rslave,
Shared,
Slave,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum Recursive {
Disabled,
Enabled,
Readonly,
Writable,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
pub enum SELinux {
#[serde(rename = "z")]
Shared,
#[serde(rename = "Z")]
Unshared,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct Bind {
#[serde(skip_serializing_if = "Option::is_none")]
pub create_host_path: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub propagation: Option<Propagation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recursive: Option<Recursive>,
#[serde(skip_serializing_if = "Option::is_none")]
pub selinux: Option<SELinux>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct VolumeSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub labels: Option<ListOrMap>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nocopy: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub subpath: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct ImageVolumeSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub subpath: Option<String>,
}
#[derive(Clone, Debug, Serialize, Default, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub struct TmpfsSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<StringOrNum>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum PortMode {
Host,
Ingress,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum Protocol {
Tcp,
Udp,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(untagged)]
pub enum Port {
Num(u64),
String(String),
Data(PortSettings),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Default)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct PortSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub host_ip: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub published: Option<StringOrNum>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<PortMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub protocol: Option<Protocol>,
#[serde(skip_serializing_if = "Option::is_none")]
pub app_protocol: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[cfg_attr(feature = "schemars", derive(JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum PullPolicy {
Always,
Build,
Daily,
#[serde(alias = "if_not_present")]
Missing,
Never,
Refresh,
Weekly,
#[serde(untagged)]
Other(String),
}