diff --git a/image.go b/image.go index fb3c03cf345df29623f63595fc545f365d0fe2af..c66ec77eb38bbd659af2c3c181a0be39cbd87490 100644 --- a/image.go +++ b/image.go @@ -22,6 +22,14 @@ type Image struct { Tag string } +// 新建一个镜像 +func NewImage(name string, tag string) Image { + return Image{ + Name: name, + Tag: tag, + } +} + func (m Image) MarshalYAML() (result interface{}, err error) { if len(m.Name) == 0 { err = errors.New("docker: image name can not be empty") diff --git a/secret.go b/secret.go new file mode 100644 index 0000000000000000000000000000000000000000..3a3404c00dfccf9b61ff4f6af87de1da18740f2b --- /dev/null +++ b/secret.go @@ -0,0 +1,16 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +// 暴露的映射的公共接口 +type Secret interface { + IsSecret() bool +} diff --git a/secret_complex.go b/secret_complex.go new file mode 100644 index 0000000000000000000000000000000000000000..be491f06e65625cf22fdc83ba4cd7132ecdb0f5e --- /dev/null +++ b/secret_complex.go @@ -0,0 +1,25 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +// 密钥(Long Syntax) +type SecretComplex struct { + Source string `yaml:"source"` // 名称 + Target string `yaml:"target,omitempty"` // 文件名 + Uid string `yaml:"uid,omitempty"` // 文件UID + Gid string `yaml:"gid,omitempty"` // 文件GID + Mode string `yaml:"mode,omitempty"` // 文件权限 +} + +// 实现公共接口 +func (SecretComplex) IsSecret() bool { + return true +} diff --git a/secret_simple.go b/secret_simple.go new file mode 100644 index 0000000000000000000000000000000000000000..b00334299ea26bd136e5bca63ec0830151f075c1 --- /dev/null +++ b/secret_simple.go @@ -0,0 +1,55 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +import ( + "errors" +) + +// 密钥(Short Syntax) +type SecretSimple struct { + Source string // 名称 +} + +// 新建一个密钥 +func NewSecretSimple(source string) SecretSimple { + return SecretSimple{ + Source: source, + } +} + +// 实现公共接口 +func (SecretSimple) IsSecret() bool { + return true +} + +func (m SecretSimple) MarshalYAML() (result interface{}, err error) { + if len(m.Source) == 0 { + err = errors.New("docker: simple-secret source can not be empty") + return + } + result = m.Source + return +} + +func (m *SecretSimple) UnmarshalYAML(unmarshal func(interface{}) error) (err error) { + var origin string + if err = unmarshal(&origin); err != nil { + return + } + m.Source = origin + // 校验 + if len(m.Source) == 0 { + err = errors.New("docker: simple-secret format error") + return + } + return +} diff --git a/secret_simple_test.go b/secret_simple_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b1dcfb1e7b343583709165bd62798fe3d52ab102 --- /dev/null +++ b/secret_simple_test.go @@ -0,0 +1,52 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +import ( + "fmt" + "testing" +) + +func TestSecretSimple(t *testing.T) { + tests := []struct { + item string + wantSource string + wantErr bool + }{ + {item: "my_secret", wantSource: "my_secret", wantErr: false}, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + // MarshalYaml + if !tt.wantErr { + item := SecretSimple{Source: tt.wantSource} + result, _ := item.MarshalYAML() + content := fmt.Sprintf("%s", result) + if content != tt.item { + t.Logf("%d %d", len(content), len(tt.item)) + t.Errorf("SecretSimple.MarshalYAML() content = %v, wantContent %v", content, tt.item) + return + } + } + // UnmarshalYaml + var item SecretSimple + err := UnmarshalYaml(tt.item, &item) + if (err != nil) != tt.wantErr { + t.Errorf("SecretSimple.UnarshalYAML() error = %v, wantErr %v", err, tt.wantErr) + return + } + if item.Source != tt.wantSource { + t.Errorf("SecretSimple.UnarshalYAML() source = %v, wantSouce %v", item.Source, tt.wantSource) + return + } + }) + } +} diff --git a/service.go b/service.go index 12714b70cc8bcd0f423152fbbf06b36ec42398ee..244383047bf942a2dc648f4c7fcd712b8bab4a03 100644 --- a/service.go +++ b/service.go @@ -41,9 +41,9 @@ type Service struct { // TODO network_mode Networks map[string]NetworkMap `yaml:"networks,omitempty"` // 加入的网络 // TODO pid - Ports []Port `yaml:"ports,omitempty"` // 暴露的端口号 - Restart string `yaml:"restart,omitempty"` // 重启策略 - // TODO secrets + Ports []Port `yaml:"ports,omitempty"` // 暴露的端口号 + Restart string `yaml:"restart,omitempty"` // 重启策略 + Secrets []Secret `yaml:"secrets,omitempty"` // 密钥 // TODO security_opt // TODO stop_grace_period // TODO stop_signal diff --git a/volume_map.go b/volume_map.go index b329a7af6a70de1962fc843475ef906799c7f30d..d0c4ec4e01fc76eaf2d91054d4a1f0c24a738cdb 100644 --- a/volume_map.go +++ b/volume_map.go @@ -10,14 +10,7 @@ package docker -// 挂载卷 -type VolumeMap struct { - Type string `yaml:"type"` // 挂载类型 - Source string `yaml:"source"` // 外部的源地址 - Target string `yaml:"target"` // 容器内的目标地址 - ReadOnly string `yaml:"read_only,omitempty"` // 只读标志 - // TODO bind - // TODO volume - // TODO tmpfs - // TODO consistency +// 暴露的路径映射的公共接口 +type VolumeMap interface { + IsVolumeMap() bool } diff --git a/volume_map_complex.go b/volume_map_complex.go new file mode 100644 index 0000000000000000000000000000000000000000..e8c25f61107d1250bec31d0caecc05f37948987a --- /dev/null +++ b/volume_map_complex.go @@ -0,0 +1,28 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +// 挂载卷 +type VolumeMapComplex struct { + Type string `yaml:"type"` // 挂载类型 + Source string `yaml:"source"` // 外部的源地址 + Target string `yaml:"target"` // 容器内的目标地址 + ReadOnly string `yaml:"read_only,omitempty"` // 只读标志 + // TODO bind + // TODO volume + // TODO tmpfs + // TODO consistency +} + +// 实现公共接口 +func (VolumeMapComplex) IsVolumeMap() bool { + return true +} diff --git a/volume_map_simple.go b/volume_map_simple.go new file mode 100644 index 0000000000000000000000000000000000000000..b196ae39e108dc08d95e2b7faad1b88810342b22 --- /dev/null +++ b/volume_map_simple.go @@ -0,0 +1,90 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +import ( + "errors" + "fmt" + "strings" +) + +// 路径(Short Syntax) +type VolumeMapSimple struct { + Host string // 外部主机的路径 + Container string // 内部容器的路径 + Mode string // 权限 +} + +// 新建一个路径A到路径B的映射 +func NewVolumeMapSimple(hostVolumeMap string, containerVolumeMap string) VolumeMapSimple { + return VolumeMapSimple{ + Host: hostVolumeMap, + Container: containerVolumeMap, + } +} + +// 新建一个相同的路径映射 +func NewVolumeMapSimpleSame(volumeMap string) VolumeMapSimple { + volumeMapSimple := NewVolumeMapSimple(volumeMap, volumeMap) + volumeMapSimple.Mode = VolumeReadOnly + return volumeMapSimple +} + +// 实现公共接口 +func (VolumeMapSimple) IsVolumeMap() bool { + return true +} + +func (m VolumeMapSimple) MarshalYAML() (result interface{}, err error) { + if len(m.Host) == 0 { + err = errors.New("docker: simple-volume-map host can not be empty") + return + } + tmp := m.Host + if len(m.Container) > 0 { + tmp += fmt.Sprintf(":%s", m.Container) + if len(m.Mode) > 0 { + tmp += fmt.Sprintf(":%s", m.Mode) + } + } + result = tmp + return +} + +func (m *VolumeMapSimple) UnmarshalYAML(unmarshal func(interface{}) error) (err error) { + var origin string + if err = unmarshal(&origin); err != nil { + return + } + // 拆分 + parts := strings.Split(origin, ":") + if len(parts) > 3 { + err = errors.New("docker: simple-volume-map format error") + return + } + m.Host = parts[0] + if len(parts) > 1 { + m.Container = parts[1] + } + if len(parts) > 2 { + m.Mode = parts[2] + } + // 校验 + if len(m.Host) == 0 { + err = errors.New("docker: simple-volume-map format error") + return + } + if len(m.Container) == 0 && len(m.Mode) > 0 { + err = errors.New("docker: simple-volume-map format error") + return + } + return +} diff --git a/volume_map_simple_test.go b/volume_map_simple_test.go new file mode 100644 index 0000000000000000000000000000000000000000..538e12b56e4fe818c39d34fcdbfa97ad88b6bb13 --- /dev/null +++ b/volume_map_simple_test.go @@ -0,0 +1,70 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +import ( + "fmt" + "strings" + "testing" +) + +func TestVolumeMapSimple(t *testing.T) { + tests := []struct { + item string + wantHost string + wantContainer string + wantMode string + wantErr bool + }{ + {item: "/var/lib/mysql", wantHost: "/var/lib/mysql", wantErr: false}, + {item: "/opt/data:/var/lib/mysql", wantHost: "/opt/data", wantContainer: "/var/lib/mysql", wantErr: false}, + {item: "./cache:/tmp/cache", wantHost: "./cache", wantContainer: "/tmp/cache", wantErr: false}, + {item: "~/configs:/udp", wantHost: "~/configs", wantContainer: "/udp", wantErr: false}, + {item: "~/configs:/etc/configs/:ro", wantHost: "~/configs", wantContainer: "/etc/configs/", wantMode: "ro", wantErr: false}, + {item: "datavolume:/var/lib/mysql", wantHost: "datavolume", wantContainer: "/var/lib/mysql", wantErr: false}, + {item: "datavolume::ro", wantHost: "datavolume", wantContainer: "", wantMode: "ro", wantErr: true}, + {item: ":/var/lib/mysql", wantHost: "", wantContainer: "/var/lib/mysql", wantMode: "", wantErr: true}, + } + for i, tt := range tests { + t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { + // MarshalYaml + if !tt.wantErr { + item := VolumeMapSimple{Host: tt.wantHost, Container: tt.wantContainer, Mode: tt.wantMode} + content := MarshalYaml(item) + content = strings.TrimRight(content, "\n") + if content != tt.item { + t.Logf("%d %d", len(content), len(tt.item)) + t.Errorf("VolumeMapSimple.MarshalYAML() content = %v, wantContent %v", content, tt.item) + return + } + } + // UnmarshalYaml + var item VolumeMapSimple + err := UnmarshalYaml(tt.item, &item) + if (err != nil) != tt.wantErr { + t.Errorf("VolumeMapSimple.UnarshalYAML() error = %v, wantErr %v", err, tt.wantErr) + return + } + if item.Host != tt.wantHost { + t.Errorf("VolumeMapSimple.UnarshalYAML() host = %v, wantHost %v", item.Host, tt.wantHost) + return + } + if item.Container != tt.wantContainer { + t.Errorf("Image.UnarshalYAML() container = %v, wantContainer %v", item.Container, tt.wantContainer) + return + } + if item.Mode != tt.wantMode { + t.Errorf("VolumeMapSimple.UnarshalYAML() mode = %v, wantMode %v", item.Mode, tt.wantMode) + return + } + }) + } +} diff --git a/yml.go b/yml.go index 372912cd33b0e0f56f93e44a9bfa388d01e48518..6b39aa2816ef9f6fa223cd9c342cd7c73ad8da49 100644 --- a/yml.go +++ b/yml.go @@ -12,12 +12,12 @@ package docker // 完整的配置文件 type Yml struct { - Version string `yaml:"version"` // 版本号 - Services map[string]Service `yaml:"services"` // 服务配置 - Volumes map[string]Volume `yaml:"volumes,omitempty"` // 挂载卷配置 - Networks map[string]Network `yaml:"networks,omitempty"` // 网络配置 + Version string `yaml:"version"` // 版本号 + Services map[string]Service `yaml:"services"` // 服务配置 + Volumes map[string]Volume `yaml:"volumes,omitempty"` // 挂载卷配置 + Networks map[string]Network `yaml:"networks,omitempty"` // 网络配置 + Secrets map[string]YmlSecret `yaml:"secrets,omitempty"` // 密钥 // TODO configs - // TODO secrets // TODO Variable substitution // TODO Extension fields } diff --git a/yml_secret.go b/yml_secret.go new file mode 100644 index 0000000000000000000000000000000000000000..d7967e91e29e3056b67af4622c7a64ffc3ff8326 --- /dev/null +++ b/yml_secret.go @@ -0,0 +1,18 @@ +/* + Copyright (c) 2020 XiaochengTech + gitee.com/xiaochengtech/docker is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. +*/ + +package docker + +// 暴露的映射的公共接口 +type YmlSecret struct { + File string `yaml:"file,omitempty"` // 文件路径 + External string `yaml:"external,omitempty"` // 是否已存在,存在不需要再创建。 + Name string `yaml:"name,omitempty"` // (v3.5+) 名称 +}