Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement LoadPlainYAMLManifests and LoadManifests #5284

Merged
merged 1 commit into from
Oct 22, 2024
Merged
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
19 changes: 19 additions & 0 deletions pkg/app/pipedv1/plugin/kubernetes/provider/kubernetes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2024 The PipeCD 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 provider

const (
AnnotationOrder = "pipecd.dev/order" // The order number of resource used to sort them before using.
)
166 changes: 166 additions & 0 deletions pkg/app/pipedv1/plugin/kubernetes/provider/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,172 @@

package provider

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"slices"
"strconv"
"strings"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"

"github.com/pipe-cd/pipecd/pkg/model"
)

type TemplatingMethod string

const (
TemplatingMethodHelm TemplatingMethod = "helm"
TemplatingMethodKustomize TemplatingMethod = "kustomize"
TemplatingMethodNone TemplatingMethod = "none"
)

type LoaderInput struct {
AppDir string
ConfigFilename string
Manifests []string

Namespace string
TemplatingMethod TemplatingMethod

// TODO: define fields for LoaderInput.
}

type Loader struct {
}

func (l *Loader) LoadManifests(input LoaderInput) (manifests []Manifest, err error) {
defer func() {
// Override namespace if set because ParseManifests does not parse it
// if namespace is not explicitly specified in the manifests.
setNamespace(manifests, input.Namespace)
sortManifests(manifests)
}()

Check warning on line 61 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L55-L61

Added lines #L55 - L61 were not covered by tests

switch input.TemplatingMethod {
case TemplatingMethodHelm:
return nil, errors.New("not implemented yet")
case TemplatingMethodKustomize:
return nil, errors.New("not implemented yet")
case TemplatingMethodNone:
return LoadPlainYAMLManifests(input.AppDir, input.Manifests, input.ConfigFilename)
default:
return nil, fmt.Errorf("unsupported templating method %s", input.TemplatingMethod)

Check warning on line 71 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L63-L71

Added lines #L63 - L71 were not covered by tests
}
}

func setNamespace(manifests []Manifest, namespace string) {
if namespace == "" {
return
}
for i := range manifests {
manifests[i].Key.Namespace = namespace
}

Check warning on line 81 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L75-L81

Added lines #L75 - L81 were not covered by tests
}

func sortManifests(manifests []Manifest) {
if len(manifests) < 2 {
return
}

Check warning on line 87 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L84-L87

Added lines #L84 - L87 were not covered by tests

slices.SortFunc(manifests, func(a, b Manifest) int {
iAns := a.Body.GetAnnotations()
// Ignore the converting error since it is not so much important.
iIndex, _ := strconv.Atoi(iAns[AnnotationOrder])

jAns := b.Body.GetAnnotations()
// Ignore the converting error since it is not so much important.
jIndex, _ := strconv.Atoi(jAns[AnnotationOrder])

return iIndex - jIndex
})

Check warning on line 99 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L89-L99

Added lines #L89 - L99 were not covered by tests
}

func LoadPlainYAMLManifests(dir string, names []string, configFilename string) ([]Manifest, error) {
// If no name was specified we have to walk the app directory to collect the manifest list.
if len(names) == 0 {
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}

Check warning on line 108 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L107-L108

Added lines #L107 - L108 were not covered by tests
if path == dir {
return nil
}
if d.IsDir() {
return fs.SkipDir
}

Check warning on line 114 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L113-L114

Added lines #L113 - L114 were not covered by tests
if ext := filepath.Ext(d.Name()); ext != ".yaml" && ext != ".yml" && ext != ".json" {
return nil
}

Check warning on line 117 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L116-L117

Added lines #L116 - L117 were not covered by tests
if model.IsApplicationConfigFile(d.Name()) {
// MEMO: can we remove this check because we have configFilename?
return nil
}

Check warning on line 121 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L119-L121

Added lines #L119 - L121 were not covered by tests
if d.Name() == configFilename {
return nil
}
names = append(names, d.Name())
return nil
})
if err != nil {
return nil, err
}

Check warning on line 130 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L129-L130

Added lines #L129 - L130 were not covered by tests
}

manifests := make([]Manifest, 0, len(names))
for _, name := range names {
path := filepath.Join(dir, name)
ms, err := LoadManifestsFromYAMLFile(path)
if err != nil {
return nil, fmt.Errorf("failed to load manifest at %s (%w)", path, err)
}
manifests = append(manifests, ms...)
}

return manifests, nil
}

// LoadManifestsFromYAMLFile loads the manifests from the given file.
func LoadManifestsFromYAMLFile(path string) ([]Manifest, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}

Check warning on line 151 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L150-L151

Added lines #L150 - L151 were not covered by tests
return ParseManifests(string(data))
}

// ParseManifests parses the given data and returns a list of Manifest.
func ParseManifests(data string) ([]Manifest, error) {
const separator = "\n---"
var (
parts = strings.Split(data, separator)
manifests = make([]Manifest, 0, len(parts))
)

for i, part := range parts {
// Ignore all the cases where no content between separator.
if len(strings.TrimSpace(part)) == 0 {
continue
}
// Append new line which trim by document separator.
if i != len(parts)-1 {
part += "\n"
}
var obj unstructured.Unstructured
if err := yaml.Unmarshal([]byte(part), &obj); err != nil {
return nil, err
}
if len(obj.Object) == 0 {
continue

Check warning on line 177 in pkg/app/pipedv1/plugin/kubernetes/provider/loader.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/kubernetes/provider/loader.go#L177

Added line #L177 was not covered by tests
}
manifests = append(manifests, Manifest{
Key: MakeResourceKey(&obj),
Body: &obj,
})
}
return manifests, nil
}
Loading
Loading