Skip to content

Commit

Permalink
fix TestLoadSSH*
Browse files Browse the repository at this point in the history
Signed-off-by: Nicolas De Loof <[email protected]>
  • Loading branch information
ndeloof committed Oct 13, 2023
1 parent 246937b commit 14595c9
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 179 deletions.
73 changes: 0 additions & 73 deletions loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,15 +681,10 @@ func createTransformHook(additionalTransformers ...Transformer) mapstructure.Dec
reflect.TypeOf(types.ServiceSecretConfig{}): transformFileReferenceConfig,
reflect.TypeOf(types.ServiceConfigObjConfig{}): transformFileReferenceConfig,
reflect.TypeOf(map[string]*types.ServiceNetworkConfig{}): transformServiceNetworkMap,
reflect.TypeOf(types.Mapping{}): transformMappingOrListFunc("=", false),
reflect.TypeOf(types.MappingWithEquals{}): transformMappingOrListFunc("=", true),
reflect.TypeOf(types.MappingWithColon{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.HostsList{}): transformMappingOrListFunc(":", false),
reflect.TypeOf(types.ServiceVolumeConfig{}): transformServiceVolumeConfig,
reflect.TypeOf(types.BuildConfig{}): transformBuildConfig,
reflect.TypeOf(types.DependsOnConfig{}): transformDependsOnConfig,
reflect.TypeOf(types.ExtendsConfig{}): transformExtendsConfig,
reflect.TypeOf(types.SSHConfig{}): transformSSHConfig,
reflect.TypeOf(types.IncludeConfig{}): transformIncludeConfig,
}

Expand Down Expand Up @@ -1221,74 +1216,6 @@ var transformServiceNetworkMap TransformerFunc = func(value interface{}) (interf
return value, nil
}

var transformSSHConfig TransformerFunc = func(data interface{}) (interface{}, error) {
switch value := data.(type) {
case map[string]interface{}:
var result []types.SSHKey
for key, val := range value {
if val == nil {
val = ""
}
result = append(result, types.SSHKey{ID: key, Path: val.(string)})
}
return result, nil
case []interface{}:
var result []types.SSHKey
for _, v := range value {
key, val := transformValueToMapEntry(v.(string), "=", false)
result = append(result, types.SSHKey{ID: key, Path: val.(string)})
}
return result, nil
case string:
return ParseShortSSHSyntax(value)
}
return nil, errors.Errorf("expected a sting, map or a list, got %T: %#v", data, data)
}

// ParseShortSSHSyntax parse short syntax for SSH authentications
func ParseShortSSHSyntax(value string) ([]types.SSHKey, error) {
if value == "" {
value = "default"
}
key, val := transformValueToMapEntry(value, "=", false)
result := []types.SSHKey{{ID: key, Path: val.(string)}}
return result, nil
}

func transformMappingOrListFunc(sep string, allowNil bool) TransformerFunc {
return func(data interface{}) (interface{}, error) {
return transformMappingOrList(data, sep, allowNil)
}
}

func transformMappingOrList(mappingOrList interface{}, sep string, allowNil bool) (interface{}, error) {
switch value := mappingOrList.(type) {
case map[string]interface{}:
return toMapStringString(value, allowNil), nil
case []interface{}:
result := make(map[string]interface{})
for _, value := range value {
key, val := transformValueToMapEntry(value.(string), sep, allowNil)
result[key] = val
}
return result, nil
}
return nil, errors.Errorf("expected a map or a list, got %T: %#v", mappingOrList, mappingOrList)
}

func transformValueToMapEntry(value string, separator string, allowNil bool) (string, interface{}) {
parts := strings.SplitN(value, separator, 2)
key := parts[0]
switch {
case len(parts) == 1 && allowNil:
return key, nil
case len(parts) == 1 && !allowNil:
return key, ""
default:
return key, parts[1]
}
}

func toMapStringString(value map[string]interface{}, allowNil bool) map[string]interface{} {
output := make(map[string]interface{})
for key, value := range value {
Expand Down
73 changes: 1 addition & 72 deletions loader/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,78 +965,7 @@ services:
}, config.Services)
}

// Issue#972
func TestLoadMultipleNetworks(t *testing.T) {
base := map[string]interface{}{
"services": map[string]interface{}{
"foo": map[string]interface{}{
"image": "baz",
},
},
"volumes": map[string]interface{}{},
"networks": map[string]interface{}{
"hostnet": map[string]interface{}{
"driver": "overlay",
"ipam": map[string]interface{}{
"driver": "default",
"config": []interface{}{
map[string]interface{}{
"subnet": "10.0.0.0/20",
},
},
},
},
},
"secrets": map[string]interface{}{},
"configs": map[string]interface{}{},
}
override := map[string]interface{}{
"services": map[string]interface{}{},
"volumes": map[string]interface{}{},
"networks": map[string]interface{}{
"hostnet": map[string]interface{}{
"external": map[string]interface{}{
"name": "host",
},
},
},
"secrets": map[string]interface{}{},
"configs": map[string]interface{}{},
}
configDetails := types.ConfigDetails{
ConfigFiles: []types.ConfigFile{
{Filename: "base.yml", Config: base},
{Filename: "override.yml", Config: override},
},
}
config, err := loadTestProject(configDetails)
assert.NilError(t, err)
assert.DeepEqual(t, &types.Project{
Name: "",
WorkingDir: "",
Services: []types.ServiceConfig{
{
Name: "foo",
Image: "baz",
Environment: types.MappingWithEquals{},
Scale: 1,
}},
Networks: map[string]types.NetworkConfig{
"hostnet": {
Name: "host",
External: types.External{
External: true,
},
},
},
Volumes: types.Volumes{},
Secrets: types.Secrets{},
Configs: types.Configs{},
Extensions: types.Extensions{},
}, config)
}

func TestMergeUlimitsConfig(t *testing.T) {
func TestMergUlimitsConfig(t *testing.T) {
specials := &specials{
m: map[reflect.Type]func(dst, src reflect.Value) error{
reflect.TypeOf(&types.UlimitsConfig{}): mergeUlimitsConfig,
Expand Down
2 changes: 1 addition & 1 deletion transform/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func transformBuild(data any, p tree.Path) (any, error) {
if _, ok := v["context"]; !ok {
v["context"] = "." // TODO(ndeloof) maybe we miss an explicit "set-defaults" loading phase
}
return v, nil
return transformMapping(v, p)
case string:
return map[string]any{
"context": v,
Expand Down
1 change: 1 addition & 0 deletions transform/canonical.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func init() {
transformers["services.*.volumes.*"] = transformVolumeMount
transformers["services.*.ports"] = transformPorts
transformers["services.*.build"] = transformBuild
transformers["services.*.build.ssh"] = transformSSH
transformers["services.*.ulimits.*"] = transformUlimits
transformers["volumes.*"] = transformMaybeExternal
transformers["networks.*"] = transformMaybeExternal
Expand Down
45 changes: 45 additions & 0 deletions transform/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package transform

import (
"fmt"

"github.com/compose-spec/compose-go/tree"
"github.com/pkg/errors"
)

func transformSSH(data any, p tree.Path) (any, error) {
switch v := data.(type) {
case map[string]any:
result := make([]any, len(v))
i := 0
for k, e := range v {
if e == nil {
result[i] = k
} else {
result[i] = fmt.Sprintf("%s=%s", k, e)
}
i++
}
return result, nil
case []any:
return data, nil
default:
return data, errors.Errorf("invalid type %T for ssh", v)
}
}
1 change: 1 addition & 0 deletions transform/ssh_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package transform
74 changes: 74 additions & 0 deletions types/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
Copyright 2020 The Compose Specification Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package types

import (
"fmt"
"strings"
)

type SSHKey struct {
ID string `yaml:"id,omitempty" json:"id,omitempty"`
Path string `path:"path,omitempty" json:"path,omitempty"`
}

// SSHConfig is a mapping type for SSH build config
type SSHConfig []SSHKey

func (s SSHConfig) Get(id string) (string, error) {
for _, sshKey := range s {
if sshKey.ID == id {
return sshKey.Path, nil
}
}
return "", fmt.Errorf("ID %s not found in SSH keys", id)
}

// MarshalYAML makes SSHKey implement yaml.Marshaller
func (s SSHKey) MarshalYAML() (interface{}, error) {
if s.Path == "" {
return s.ID, nil
}
return fmt.Sprintf("%s=%s", s.ID, s.Path), nil
}

// MarshalJSON makes SSHKey implement json.Marshaller
func (s SSHKey) MarshalJSON() ([]byte, error) {
if s.Path == "" {
return []byte(fmt.Sprintf(`%q`, s.ID)), nil
}
return []byte(fmt.Sprintf(`%q=%s`, s.ID, s.Path)), nil
}

func (s *SSHKey) DecodeMapstructure(value interface{}) error {
v, ok := value.(string)
if !ok {
return fmt.Errorf("invalid ssh key type %T", value)
}
id, path, ok := strings.Cut(v, "=")
key := SSHKey{ID: id}
if !ok {
if id != "default" {
return fmt.Errorf("invalid ssh key syntax %q", value)
}
}
if path != "" {
key.Path = path
}
*s = key
return nil
}
33 changes: 0 additions & 33 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,39 +328,6 @@ type ThrottleDevice struct {
Extensions Extensions `yaml:"#extensions,inline" json:"-"`
}

type SSHKey struct {
ID string
Path string
}

// SSHConfig is a mapping type for SSH build config
type SSHConfig []SSHKey

func (s SSHConfig) Get(id string) (string, error) {
for _, sshKey := range s {
if sshKey.ID == id {
return sshKey.Path, nil
}
}
return "", fmt.Errorf("ID %s not found in SSH keys", id)
}

// MarshalYAML makes SSHKey implement yaml.Marshaller
func (s SSHKey) MarshalYAML() (interface{}, error) {
if s.Path == "" {
return s.ID, nil
}
return fmt.Sprintf("%s: %s", s.ID, s.Path), nil
}

// MarshalJSON makes SSHKey implement json.Marshaller
func (s SSHKey) MarshalJSON() ([]byte, error) {
if s.Path == "" {
return []byte(fmt.Sprintf(`%q`, s.ID)), nil
}
return []byte(fmt.Sprintf(`%q: %s`, s.ID, s.Path)), nil
}

// MappingWithColon is a mapping type that can be converted from a list of
// 'key: value' strings
type MappingWithColon map[string]string
Expand Down

0 comments on commit 14595c9

Please sign in to comment.