Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions files/tests/sanitization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,17 @@ func TestSanitizeFile(t *testing.T) {
".zip": true,
}

tempDir, _ := os.MkdirTemp(" ", "temp-tests")
defer os.RemoveAll(tempDir)
// tempDir := "./temp"
// Create a temporary directory for the tests and handle potential errors.
tempDir, err := os.MkdirTemp(" ", "temp-tests")
if err != nil {
t.Fatalf("Failed to create temporary directory: %v", err)
}
// Defer cleanup and log any error that occurs during cleanup.
defer func() {
if err := os.RemoveAll(tempDir); err != nil {
t.Logf("Warning: failed to remove temporary directory %s: %v", tempDir, err)
}
}()

for _, tc := range testCases {

Expand Down
19 changes: 16 additions & 3 deletions generators/github/git_repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,28 @@ import (
"strings"

"github.com/meshery/meshkit/generators/models"
"github.com/meshery/meshkit/logger"
"github.com/meshery/meshkit/utils"
"github.com/meshery/meshkit/utils/helm"
"github.com/meshery/meshkit/utils/walker"
)

type GitRepo struct {
// <git://github.com/owner/repo/branch/versiontag/root(path to the directory/file)>
URL *url.URL
URL *url.URL
PackageName string
}

// Assumpations: 1. Always a K8s manifest
// 2. Unzipped/unarchived File type

func (gr GitRepo) GetContent() (models.Package, error) {
log, err := logger.New("generators-github", logger.Options{})
if err != nil {
// If logger fails to initialize, we can't proceed without logging capabilities.
// Alternatively, one could fall back to fmt.Println and continue.
return nil, err
}
gitWalker := walker.NewGit()

owner, repo, branch, root, err := gr.extractRepoDetailsFromSourceURL()
Expand All @@ -47,9 +54,15 @@ func (gr GitRepo) GetContent() (models.Package, error) {
br := bufio.NewWriter(fd)

defer func() {
br.Flush()
fd.Close()
if err := br.Flush(); err != nil {
log.Warnf("failed to flush writer: %v", err)
}

if err := fd.Close(); err != nil {
log.Warnf("failed to close file: %v", err)
}
}()

gw := gitWalker.
Owner(owner).
Repo(repo).
Expand Down
2 changes: 1 addition & 1 deletion utils/cue.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func Lookup(rootVal cue.Value, path string) (cue.Value, error) {
return res, ErrCueLookup(res.Err())
}
if !res.Exists() {
return res, ErrCueLookup(fmt.Errorf("Could not find the value at the path: %s", path))
return res, ErrCueLookup(fmt.Errorf("could not find the value at the path: %s", path))
}

return res.Value(), nil
Expand Down
46 changes: 29 additions & 17 deletions utils/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@ var (
ErrCreateDirCode = "meshkit-11182"
// ErrDecodeYamlCode represents the error which is generated when yaml
// decode process fails
ErrDecodeYamlCode = "meshkit-11183"
ErrExtractTarXZCode = "meshkit-11184"
ErrExtractZipCode = "meshkit-11185"
ErrReadDirCode = "meshkit-11186"
ErrInvalidSchemaVersionCode = "meshkit-11273"
ErrFileWalkDirCode = "meshkit-11274"
ErrRelPathCode = "meshkit-11275"
ErrCopyFileCode = "meshkit-11276"
ErrCloseFileCode = "meshkit-11277"
ErrCompressToTarGZCode = "meshkit-11248"
ErrDecodeYamlCode = "meshkit-11183"
ErrExtractTarXZCode = "meshkit-11184"
ErrExtractZipCode = "meshkit-11185"
ErrReadDirCode = "meshkit-11186"
ErrInvalidSchemaVersionCode = "meshkit-11273"
ErrFileWalkDirCode = "meshkit-11274"
ErrRelPathCode = "meshkit-11275"
ErrCopyFileCode = "meshkit-11276"
ErrCloseFileCode = "meshkit-11277"
ErrCompressToTarGZCode = "meshkit-11248"
ErrUnsupportedTarHeaderTypeCode = "meshkit-11282"

ErrConvertToByteCode = "meshkit-11187"

Expand All @@ -64,9 +65,9 @@ func ErrInvalidConstructSchemaVersion(contruct string, version string, supported
ErrInvalidSchemaVersionCode,
errors.Critical,
[]string{"Invalid schema version " + version},
[]string{"The `schemaVersion` key is either empty or has an incorrect value."},
[]string{"The schemaVersion key is either empty or has an incorrect value."},
[]string{fmt.Sprintf("The schema is not of type '%s'", contruct)},
[]string{"Verify that `schemaVersion` key should be '%s'", supportedVersion},
[]string{"Verify that schemaVersion key should be '%s'", supportedVersion},
)
}

Expand All @@ -75,17 +76,17 @@ var (
ErrUnmarshalTypeCode,
errors.Alert,
[]string{"Invalid extraction type"},
[]string{"The file type to be extracted is neither `tar.gz` nor `zip`."},
[]string{"Invalid object format. The file is not of type `zip` or `tar.gz`."},
[]string{"Make sure to check that the file type is `zip` or `tar.gz`."},
[]string{"The file type to be extracted is neither tar.gz nor zip."},
[]string{"Invalid object format. The file is not of type zip or tar.gz."},
[]string{"Make sure to check that the file type is zip or tar.gz."},
)
ErrInvalidSchemaVersion = errors.New(
ErrInvalidSchemaVersionCode,
errors.Alert,
[]string{"Invalid schema version"},
[]string{"The `schemaVersion` key is either empty or has an incorrect value."},
[]string{"The schemaVersion key is either empty or has an incorrect value."},
[]string{"The schema is not of type 'relationship', 'component', 'model' , 'policy'."},
[]string{"Verify that `schemaVersion` key should be either `relationships.meshery.io`, `component.meshery.io`, `model.meshery.io` or `policy.meshery.io`."},
[]string{"Verify that schemaVersion key should be either relationships.meshery.io, component.meshery.io, model.meshery.io or policy.meshery.io."},
)
)

Expand Down Expand Up @@ -272,3 +273,14 @@ func ErrGoogleSheetSRV(err error) error {
func ErrWritingIntoFile(err error, obj string) error {
return errors.New(ErrWritingIntoFileCode, errors.Alert, []string{fmt.Sprintf("failed to write into file %s", obj)}, []string{err.Error()}, []string{"Insufficient permissions to write into file", "file might be corrupted"}, []string{"check if sufficient permissions are givent to the file", "check if the file is corrupted"})
}

func ErrUnsupportedTarHeaderType(typeflag byte, name string) error {
return errors.New(
ErrUnsupportedTarHeaderTypeCode,
errors.Alert,
[]string{"Unsupported tar header type encountered during extraction"},
[]string{fmt.Sprintf("The tar archive contains an entry '%s' with an unsupported type flag '%c'.", name, typeflag)},
[]string{"The tar archive is malformed or contains an entry type that this utility cannot handle (e.g., special device files)."},
[]string{"Ensure the tar archive was created with standard file types (directories, regular files, symlinks).", "Check the integrity of the archive file."},
)
}
85 changes: 61 additions & 24 deletions utils/kubernetes/kompose/convert.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kompose

import (
"fmt"
"os"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -42,37 +43,55 @@ func Convert(dockerCompose DockerComposeFile) (string, error) {
tempFilePath := filepath.Join(mesheryDir, "temp.data")
resultFilePath := filepath.Join(mesheryDir, "result.yaml")

// Defer cleanup to ensure temp files are removed even on error.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not util IMO

defer func() {
// We log cleanup errors but do not return them, as the primary function error is more important.
if err := os.Remove(tempFilePath); err != nil && !os.IsNotExist(err) {
// A logger should be used here to warn about the failed cleanup.
// e.g., log.Warnf("failed to remove temporary file %s: %v", tempFilePath, err)
Comment on lines +50 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not log here ?

}
if err := os.Remove(resultFilePath); err != nil && !os.IsNotExist(err) {
// e.g., log.Warnf("failed to remove result file %s: %v", resultFilePath, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

}
}()

// Create the temp file
if err := utils.CreateFile(dockerCompose, "temp.data", mesheryDir); err != nil {
return "", ErrCvrtKompose(err)
}

defer func() {
os.Remove(tempFilePath)
os.Remove(resultFilePath)
}()
// Format Docker Compose file for Kompose
err = formatComposeFile(&dockerCompose)
if err != nil {
return "", ErrCvrtKompose(err)
}

formatComposeFile(&dockerCompose)
// Check version compatibility
err = versionCheck(dockerCompose)
if err != nil {
return "", ErrCvrtKompose(err)
}

// Initialize Kompose client
komposeClient, err := client.NewClient()
if err != nil {
return "", ErrCvrtKompose(err)
}

// Set up Convert options
ConvertOpt := client.ConvertOptions{
InputFiles: []string{tempFilePath},
OutFile: resultFilePath,
GenerateNetworkPolicies: true,
}

// Convert using Kompose client
_, err = komposeClient.Convert(ConvertOpt)
if err != nil {
return "", ErrCvrtKompose(err)
}

// Read the result file
result, err := os.ReadFile(resultFilePath)
if err != nil {
return "", ErrCvrtKompose(err)
Expand All @@ -81,13 +100,42 @@ func Convert(dockerCompose DockerComposeFile) (string, error) {
return string(result), nil
}

type composeFile struct {
Version string `yaml:"version,omitempty"`
// cleanup removes temporary files
func cleanup(tempFilePath, resultFilePath string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the advantage to extract this in a dedicate function since it is bind to those files.

Also it should be done in a defer like previous implementation to ensure the files are closed properly. Here if one of the previous action fail the files will never be closed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No more used, write ?

// Try to remove tempFilePath
if err := os.Remove(tempFilePath); err != nil {
return fmt.Errorf("failed to remove temp file %s: %w", tempFilePath, err)
}

// Try to remove resultFilePath
if err := os.Remove(resultFilePath); err != nil {
return fmt.Errorf("failed to remove result file %s: %w", resultFilePath, err)
}

return nil // No errors
}

// checks if the version is compatible with `kompose`
// expects a valid docker compose yaml
// error = nil means it is compatible
// formatComposeFile takes in a pointer to the compose file byte array and formats it
// so that it is compatible with Kompose. It expects a validated Docker Compose file.
func formatComposeFile(yamlManifest *DockerComposeFile) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we evaluate the impact on services calling this function since the signature has changed ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatComposeFile is only called once from within the Convert function in this same file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, I did not notice it was a local function. Sorry for the noise

data := composeFile{}
err := yaml.Unmarshal(*yamlManifest, &data)
if err != nil {
return fmt.Errorf("failed to unmarshal compose file: %w", err)
}

// Marshal it again to ensure it is in the correct format for Kompose
out, err := yaml.Marshal(data)
if err != nil {
return fmt.Errorf("failed to marshal compose file: %w", err)
}

*yamlManifest = out
return nil
}

// versionCheck checks if the version in the Docker Compose file is compatible with Kompose.
// It expects a valid Docker Compose YAML and returns an error if the version is not supported.
func versionCheck(dc DockerComposeFile) error {
cf := composeFile{}
err := yaml.Unmarshal(dc, &cf)
Expand All @@ -108,18 +156,7 @@ func versionCheck(dc DockerComposeFile) error {
return nil
}

// formatComposeFile takes in a pointer to the compose file byte array and formats it so that it is compatible with `Kompose`
// it expects a validated docker compose file and does not validate
func formatComposeFile(yamlManifest *DockerComposeFile) {
data := composeFile{}
err := yaml.Unmarshal(*yamlManifest, &data)
if err != nil {
return
}
// so that "3.3" and 3.3 are treated differently by `Kompose`
out, err := yaml.Marshal(data)
if err != nil {
return
}
*yamlManifest = out
// composeFile represents the structure of the Docker Compose file version.
type composeFile struct {
Version string `yaml:"version,omitempty"`
}
Loading