Merge "Split document model, add entrypoints for repos"

This commit is contained in:
Zuul 2020-03-12 21:10:26 +00:00 committed by Gerrit Code Review
commit 6fbcc26323
46 changed files with 343 additions and 302 deletions

View File

@ -22,7 +22,7 @@ func getDummyAirshipSettings(t *testing.T) *environment.AirshipCTLSettings {
fx := fixtures.Basic().One() fx := fixtures.Basic().One()
mfst.Repository = &config.Repository{ mfst.Repositories = map[string]*config.Repository{"primary": {
URLString: fx.DotGit().Root(), URLString: fx.DotGit().Root(),
CheckoutOptions: &config.RepoCheckout{ CheckoutOptions: &config.RepoCheckout{
Branch: "master", Branch: "master",
@ -31,6 +31,7 @@ func getDummyAirshipSettings(t *testing.T) *environment.AirshipCTLSettings {
Auth: &config.RepoAuth{ Auth: &config.RepoAuth{
Type: "http-basic", Type: "http-basic",
}, },
},
} }
settings.SetConfig(conf) settings.SetConfig(conf)
return settings return settings

View File

@ -2,7 +2,7 @@ apiVersion: metal3.io/v1alpha1
kind: BareMetalHost kind: BareMetalHost
metadata: metadata:
labels: labels:
airshipit.org/ephemeral: "true" airshipit.org/node-role: "control-plane"
name: master-0 name: master-0
spec: spec:
online: true online: true

View File

@ -2,7 +2,7 @@ apiVersion: v1
kind: Secret kind: Secret
metadata: metadata:
labels: labels:
airshipit.org/ephemeral: "true" airshipit.org/node-role: "control-plane"
name: node1-bmc-secret name: node1-bmc-secret
type: Opaque type: Opaque
stringData: stringData:

View File

@ -0,0 +1,2 @@
resources:
- ../../../type/test-bootstrap

View File

@ -1,2 +0,0 @@
resources:
- ../../type/test-bootstrap

View File

@ -8,12 +8,10 @@ import (
"sigs.k8s.io/kustomize/v3/pkg/types" "sigs.k8s.io/kustomize/v3/pkg/types"
"opendev.org/airship/airshipctl/pkg/document" "opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/testutil"
) )
func TestGetCloudData(t *testing.T) { func TestGetCloudData(t *testing.T) {
fSys := testutil.SetupTestFs(t, "testdata") bundle, err := document.NewBundleByPath("testdata")
bundle, err := document.NewBundle(fSys, "/", "/")
require.NoError(t, err, "Building Bundle Failed") require.NoError(t, err, "Building Bundle Failed")
tests := []struct { tests := []struct {

View File

@ -0,0 +1,41 @@
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/node-role: "control-plane"
name: node1-bmc-secret
type: Opaque
data:
netconfig: bmV0Y29uZmlnCg==
stringData:
userdata: cloud-init
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/node-role: "worker"
name: node1-bmc-secret1
type: Opaque
---
apiVersion: v1
kind: Secret
metadata:
labels:
test: nodataforcfg
name: node1-bmc-secret2
type: Opaque
data:
foo: bmV0Y29uZmlnCg==
---
apiVersion: v1
kind: Secret
metadata:
labels:
some-data: "True"
name: node1-bmc-in-secret2
type: Opaque
data:
netconfig: bmV0Y29uZmlnCg==
stringData:
userdata: cloud-init

View File

@ -34,19 +34,17 @@ func GenerateBootstrapIso(settings *environment.AirshipCTLSettings) error {
return err return err
} }
var manifest *config.Manifest
manifest, err = globalConf.CurrentContextManifest()
if err != nil {
return err
}
if err = verifyInputs(cfg); err != nil { if err = verifyInputs(cfg); err != nil {
return err return err
} }
// TODO (dukov) replace with the appropriate function once it's available // TODO (dukov) replace with the appropriate function once it's available
// in document module // in document module
docBundle, err := document.NewBundle(document.NewDocumentFs(), manifest.TargetPath, "") root, err := globalConf.CurrentContextEntryPoint(config.Ephemeral, "")
if err != nil {
return err
}
docBundle, err := document.NewBundleByPath(root)
if err != nil { if err != nil {
return err return err
} }

View File

@ -45,8 +45,7 @@ func (mc *mockContainer) GetID() string {
} }
func TestBootstrapIso(t *testing.T) { func TestBootstrapIso(t *testing.T) {
fSys := testutil.SetupTestFs(t, "testdata") bundle, err := document.NewBundleByPath("testdata/primary/site/test-site/ephemeral")
bundle, err := document.NewBundle(fSys, "/", "/")
require.NoError(t, err, "Building Bundle Failed") require.NoError(t, err, "Building Bundle Failed")
tempVol, cleanup := testutil.TempDir(t, "bootstrap-test") tempVol, cleanup := testutil.TempDir(t, "bootstrap-test")

View File

@ -39,7 +39,6 @@ func (infra *Infra) Run() error {
// Deploy method deploys documents // Deploy method deploys documents
func (infra *Infra) Deploy() error { func (infra *Infra) Deploy() error {
kctl := infra.Client.Kubectl() kctl := infra.Client.Kubectl()
var err error
ao, err := kctl.ApplyOptions() ao, err := kctl.ApplyOptions()
if err != nil { if err != nil {
return err return err
@ -56,29 +55,23 @@ func (infra *Infra) Deploy() error {
return err return err
} }
var manifest *config.Manifest kustomizePath, err := globalConf.CurrentContextEntryPoint(infra.ClusterType, config.Initinfra)
manifest, err = globalConf.CurrentContextManifest()
if err != nil { if err != nil {
return err return err
} }
b, err := document.NewBundle(infra.FileSystem, manifest.TargetPath, "") b, err := document.NewBundleByPath(kustomizePath)
if err != nil { if err != nil {
return err return err
} }
ls := document.EphemeralClusterSelector // TODO (kkalynovskyi) Add Selector that would filter by label indicating wether to deploy it to k8s
selector := document.NewSelector().ByLabel(ls) docs, err := b.GetAllDocuments()
// Get documents that are annotated to belong to initinfra
docs, err := b.Select(selector)
if err != nil { if err != nil {
return err return err
} }
if len(docs) == 0 { if len(docs) == 0 {
return document.ErrDocNotFound{ return document.ErrDocNotFound{}
Selector: selector,
}
} }
// Label every document indicating that it was deployed by initinfra module for further reference // Label every document indicating that it was deployed by initinfra module for further reference

View File

@ -28,7 +28,7 @@ func (tc TestClient) Kubectl() kubectl.Interface { return tc.MockKubectl()
const ( const (
kubeconfigPath = "testdata/kubeconfig.yaml" kubeconfigPath = "testdata/kubeconfig.yaml"
filenameRC = "testdata/replicationcontroller.yaml" filenameRC = "testdata/primary/site/test-site/ephemeral/initinfra/replicationcontroller.yaml"
airshipConfigFile = "testdata/config.yaml" airshipConfigFile = "testdata/config.yaml"
) )

View File

@ -13,20 +13,19 @@ current-context: dummy_cluster
kind: Config kind: Config
manifests: manifests:
dummy_manifest: dummy_manifest:
primary-repository-name: primary
repositories: repositories:
dummy: primary:
target-path: dummy_targetpath auth:
url: ssh-key: testdata/test-key.pem
ForceQuery: false type: ssh-key
Fragment: "" checkout:
Host: dummy.url.com branch: ""
Opaque: "" force: false
Path: "" remote-ref: ""
RawPath: "" tag: v1.0.1
RawQuery: "" url: http://dummy.url.com/primary.git
Scheme: http sub-path: primary/site/test-site
User: null
username: dummy_user
target-path: testdata target-path: testdata
modules-config: modules-config:
bootstrapInfo: bootstrapInfo:

View File

@ -4,9 +4,7 @@ metadata:
name: test-rc name: test-rc
namespace: test namespace: test
labels: labels:
airshipit.org/ephemeral: "true" airshipit.org/initinfra: "true"
name: test-rc
airship-component: "initinfra"
spec: spec:
replicas: 1 replicas: 1
template: template:

View File

@ -0,0 +1,2 @@
resources:
- initinfra

View File

@ -21,15 +21,15 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"reflect" "reflect"
"sort" "sort"
"strings" "strings"
"sigs.k8s.io/yaml"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api" clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"sigs.k8s.io/yaml"
"opendev.org/airship/airshipctl/pkg/util" "opendev.org/airship/airshipctl/pkg/util"
) )
@ -634,6 +634,28 @@ func (c *Config) CurrentContextManifest() (*Manifest, error) {
return c.Manifests[currentContext.Manifest], nil return c.Manifests[currentContext.Manifest], nil
} }
// CurrentContextEntryPoint returns path to build bundle based on clusterType and phase
// example CurrentContextEntryPoint("ephemeral", "initinfra")
func (c *Config) CurrentContextEntryPoint(clusterType string, phase string) (string, error) {
err := ValidClusterType(clusterType)
if err != nil {
return "", err
}
ccm, err := c.CurrentContextManifest()
if err != nil {
return "", err
}
_, exists := ccm.Repositories[ccm.PrimaryRepositoryName]
if !exists {
return "", ErrMissingPrimaryRepo{}
}
return path.Join(
ccm.TargetPath,
ccm.SubPath,
clusterType,
phase), nil
}
// Credential or AuthInfo related methods // Credential or AuthInfo related methods
func (c *Config) GetAuthInfo(aiName string) (*AuthInfo, error) { func (c *Config) GetAuthInfo(aiName string) (*AuthInfo, error) {
authinfo, exists := c.AuthInfos[aiName] authinfo, exists := c.AuthInfos[aiName]
@ -845,9 +867,8 @@ func (m *Manifest) Equal(n *Manifest) bool {
if n == nil { if n == nil {
return n == m return n == m
} }
repositoryEq := reflect.DeepEqual(m.Repository, n.Repository) reposEq := reflect.DeepEqual(m.Repositories, n.Repositories)
extraReposEq := reflect.DeepEqual(m.ExtraRepositories, n.ExtraRepositories) return reposEq && m.TargetPath == n.TargetPath && m.SubPath == n.SubPath
return repositoryEq && extraReposEq && m.TargetPath == n.TargetPath
} }
func (m *Manifest) String() string { func (m *Manifest) String() string {

View File

@ -11,6 +11,11 @@ const (
AirshipClusterDefaultType = Target AirshipClusterDefaultType = Target
) )
// Constants related to Phases
const (
Initinfra = "initinfra"
)
// Sorted // Sorted
var AllClusterTypes = [2]string{Ephemeral, Target} var AllClusterTypes = [2]string{Ephemeral, Target}
@ -58,3 +63,8 @@ const (
FlagUsername = "username" FlagUsername = "username"
FlagCurrent = "current" FlagCurrent = "current"
) )
// Constants related to filesystem
const (
SiteDirectory = "site"
)

View File

@ -93,3 +93,11 @@ type ErrMissingCurrentContext struct {
func (e ErrMissingCurrentContext) Error() string { func (e ErrMissingCurrentContext) Error() string {
return "Current context must be set before using --current flag" return "Current context must be set before using --current flag"
} }
// ErrMissingPrimaryRepo returned when Primary Repository is not set in context manifest
type ErrMissingPrimaryRepo struct {
}
func (e ErrMissingPrimaryRepo) Error() string {
return "Current context manifest must have primary repository set"
}

View File

@ -16,16 +16,19 @@ current-context: dummy_context
kind: Config kind: Config
manifests: manifests:
dummy_manifest: dummy_manifest:
repository: primary-repository-name: primary
auth: repositories:
ssh-key: testdata/test-key.pem primary:
type: ssh-key auth:
checkout: ssh-key: testdata/test-key.pem
branch: "" type: ssh-key
force: false checkout:
remote-ref: "" branch: ""
tag: v1.0.1 force: false
url: http://dummy.url.com remote-ref: ""
tag: v1.0.1
url: http://dummy.url.com/manifests.git
sub-path: manifests/site/test-site
target-path: /var/tmp/ target-path: /var/tmp/
modules-config: modules-config:
bootstrapInfo: bootstrapInfo:

View File

@ -1,11 +1,14 @@
repository: primary-repository-name: primary
auth: repositories:
ssh-key: testdata/test-key.pem primary:
type: ssh-key auth:
checkout: ssh-key: testdata/test-key.pem
branch: "" type: ssh-key
force: false checkout:
remote-ref: "" branch: ""
tag: v1.0.1 force: false
url: http://dummy.url.com remote-ref: ""
tag: v1.0.1
url: http://dummy.url.com/manifests.git
sub-path: manifests/site/test-site
target-path: /var/tmp/ target-path: /var/tmp/

View File

@ -6,4 +6,4 @@ checkout:
force: false force: false
remote-ref: "" remote-ref: ""
tag: v1.0.1 tag: v1.0.1
url: http://dummy.url.com url: http://dummy.url.com/manifests.git

View File

@ -113,15 +113,23 @@ type AuthInfo struct {
authInfo *kubeconfig.AuthInfo authInfo *kubeconfig.AuthInfo
} }
// Manifests is a tuple of references to a Manifest (how do Identify, collect , // Manifest is a tuple of references to a Manifest (how do Identify, collect ,
// find the yaml manifests that airship uses to perform its operations) // find the yaml manifests that airship uses to perform its operations)
type Manifest struct { type Manifest struct {
// Repositories is the map of repository adddressable by a name // PrimaryRepositoryName is a name of the repo, that contains site/<site-name> directory
Repository *Repository `json:"repository"` // and is a starting point for building document bundle
PrimaryRepositoryName string `json:"primary-repository-name"`
// ExtraRepositories is the map of extra repositories addressable by a name // ExtraRepositories is the map of extra repositories addressable by a name
ExtraRepositories map[string]*Repository `json:"extra-repositories,omitempty"` Repositories map[string]*Repository `json:"repositories,omitempty"`
// TargetPath Local Target path for working or home dirctory for all Manifest Cloned/Returned/Generated // TargetPath Local Target path for working or home dirctory for all Manifest Cloned/Returned/Generated
TargetPath string `json:"target-path"` TargetPath string `json:"target-path"`
// SubPath is a path relative to TargetPath + Path where PrimaryRepository is cloned and contains
// directories with ClusterType and Phase bundles, example:
// Repositories[PrimaryRepositoryName].Url = 'https://github.com/airshipit/treasuremap'
// SubPath = "manifests"
// you would expect that at treasuremap/manifests you would have ephemeral/initinfra and
// ephemera/target directories, containing kustomize.yaml.
SubPath string `json:"sub-path"`
} }
// Repository is a tuple that holds the information for the remote sources of manifest yaml documents. // Repository is a tuple that holds the information for the remote sources of manifest yaml documents.

View File

@ -16,6 +16,10 @@ limitations under the License.
package config package config
const (
DefaultTestPrimaryRepo = "primary"
)
// NewConfig returns a newly initialized Config object // NewConfig returns a newly initialized Config object
func NewConfig() *Config { func NewConfig() *Config {
return &Config{ return &Config{
@ -30,15 +34,19 @@ func NewConfig() *Config {
}, },
Manifests: map[string]*Manifest{ Manifests: map[string]*Manifest{
AirshipDefaultManifest: { AirshipDefaultManifest: {
Repository: &Repository{ Repositories: map[string]*Repository{
URLString: AirshipDefaultManifestRepoLocation, DefaultTestPrimaryRepo: {
CheckoutOptions: &RepoCheckout{ URLString: AirshipDefaultManifestRepoLocation,
CommitHash: "master", CheckoutOptions: &RepoCheckout{
Branch: "master", CommitHash: "master",
RemoteRef: "master", Branch: "master",
RemoteRef: "master",
},
}, },
}, },
TargetPath: "/tmp/" + AirshipDefaultManifest, TargetPath: "/tmp/" + AirshipDefaultManifest,
PrimaryRepositoryName: DefaultTestPrimaryRepo,
SubPath: AirshipDefaultManifestRepo + "/manifests/site",
}, },
}, },
ModulesConfig: &Modules{ ModulesConfig: &Modules{
@ -78,8 +86,8 @@ func NewCluster() *Cluster {
// object with non-nil maps // object with non-nil maps
func NewManifest() *Manifest { func NewManifest() *Manifest {
return &Manifest{ return &Manifest{
Repository: NewRepository(), PrimaryRepositoryName: DefaultTestPrimaryRepo,
ExtraRepositories: make(map[string]*Repository), Repositories: map[string]*Repository{DefaultTestPrimaryRepo: NewRepository()},
} }
} }

View File

@ -57,6 +57,12 @@ type Bundle interface {
GetAllDocuments() ([]Document, error) GetAllDocuments() ([]Document, error)
} }
// NewBundleByPath helper function that returns new document.Bundle interface based on clusterType and
// phase, example: helpers.NewBunde(airConfig, "ephemeral", "initinfra")
func NewBundleByPath(rootPath string) (Bundle, error) {
return NewBundle(NewDocumentFs(), rootPath, "")
}
// NewBundle is a convenience function to create a new bundle // NewBundle is a convenience function to create a new bundle
// Over time, it will evolve to support allowing more control // Over time, it will evolve to support allowing more control
// for kustomize plugins // for kustomize plugins

View File

@ -2,8 +2,8 @@ package document
const ( const (
// Selectors // Selectors
BaseAirshipSelector = "airshipit.org" BaseAirshipSelector = "airshipit.org"
EphemeralClusterSelector = BaseAirshipSelector + "/ephemeral in (True, true)" ControlNodeSelector = BaseAirshipSelector + "/node-role=control-plane"
// Labels // Labels
DeployedByLabel = BaseAirshipSelector + "/deployed" DeployedByLabel = BaseAirshipSelector + "/deployed"

View File

@ -25,19 +25,8 @@ func (s *Settings) cloneRepositories() error {
return err return err
} }
mainRepoConfig := currentManifest.Repository // Clone repositories
repository, err := repo.NewRepository(currentManifest.TargetPath, mainRepoConfig) for _, extraRepoConfig := range currentManifest.Repositories {
if err != nil {
return err
}
err = repository.Download(mainRepoConfig.ToCheckoutOptions(true).Force)
if err != nil {
return err
}
repository.Driver.Close()
// Clone extra repositories
for _, extraRepoConfig := range currentManifest.ExtraRepositories {
repository, err := repo.NewRepository(currentManifest.TargetPath, extraRepoConfig) repository, err := repo.NewRepository(currentManifest.TargetPath, extraRepoConfig)
if err != nil { if err != nil {
return err return err

View File

@ -3,7 +3,6 @@ package pull
import ( import (
"io/ioutil" "io/ioutil"
"path" "path"
"path/filepath"
"strings" "strings"
"testing" "testing"
@ -16,6 +15,7 @@ import (
"opendev.org/airship/airshipctl/pkg/config" "opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/environment" "opendev.org/airship/airshipctl/pkg/environment"
"opendev.org/airship/airshipctl/pkg/util"
"opendev.org/airship/airshipctl/testutil" "opendev.org/airship/airshipctl/testutil"
) )
@ -42,7 +42,7 @@ func TestPull(t *testing.T) {
fx := fixtures.Basic().One() fx := fixtures.Basic().One()
dummyGitDir := fx.DotGit().Root() dummyGitDir := fx.DotGit().Root()
currentManifest.Repository = &config.Repository{ currentManifest.Repositories = map[string]*config.Repository{currentManifest.PrimaryRepositoryName: {
URLString: dummyGitDir, URLString: dummyGitDir,
CheckoutOptions: &config.RepoCheckout{ CheckoutOptions: &config.RepoCheckout{
Branch: "master", Branch: "master",
@ -51,6 +51,7 @@ func TestPull(t *testing.T) {
Auth: &config.RepoAuth{ Auth: &config.RepoAuth{
Type: "http-basic", Type: "http-basic",
}, },
},
} }
tmpDir, cleanup := testutil.TempDir(t, "airshipctlPullTest-") tmpDir, cleanup := testutil.TempDir(t, "airshipctlPullTest-")
@ -58,13 +59,13 @@ func TestPull(t *testing.T) {
currentManifest.TargetPath = tmpDir currentManifest.TargetPath = tmpDir
_, err = repo2.NewRepository(".", currentManifest.Repository) _, err = repo2.NewRepository(".", currentManifest.Repositories[currentManifest.PrimaryRepositoryName])
require.NoError(err) require.NoError(err)
err = dummyPullSettings.cloneRepositories() err = dummyPullSettings.cloneRepositories()
require.NoError(err) require.NoError(err)
dummyRepoDirName := filepath.Base(dummyGitDir) dummyRepoDirName := util.GitDirNameFromURL(dummyGitDir)
assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go")) assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go"))
assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD"))
contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD"))
@ -82,14 +83,16 @@ func TestPull(t *testing.T) {
mfst := conf.Manifests["dummy_manifest"] mfst := conf.Manifests["dummy_manifest"]
dummyGitDir := fx.DotGit().Root() dummyGitDir := fx.DotGit().Root()
mfst.Repository = &config.Repository{ mfst.Repositories = map[string]*config.Repository{
URLString: dummyGitDir, mfst.PrimaryRepositoryName: {
CheckoutOptions: &config.RepoCheckout{ URLString: dummyGitDir,
Branch: "master", CheckoutOptions: &config.RepoCheckout{
ForceCheckout: false, Branch: "master",
}, ForceCheckout: false,
Auth: &config.RepoAuth{ },
Type: "http-basic", Auth: &config.RepoAuth{
Type: "http-basic",
},
}, },
} }
dummyPullSettings.SetConfig(conf) dummyPullSettings.SetConfig(conf)
@ -103,7 +106,7 @@ func TestPull(t *testing.T) {
err = dummyPullSettings.Pull() err = dummyPullSettings.Pull()
require.NoError(err) require.NoError(err)
dummyRepoDirName := filepath.Base(dummyGitDir) dummyRepoDirName := util.GitDirNameFromURL(dummyGitDir)
assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go")) assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go"))
assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD"))
contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD"))

View File

@ -28,7 +28,7 @@ type GitDriver struct {
Storer storage.Storer Storer storage.Storer
} }
func NewGitDriver(fs billy.Filesystem, s storage.Storer) *GitDriver { func NewGitDriver(fs billy.Filesystem, s storage.Storer) Adapter {
return &GitDriver{Storer: s, Filesystem: fs} return &GitDriver{Storer: s, Filesystem: fs}
} }

View File

@ -4,7 +4,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strings"
"gopkg.in/src-d/go-billy.v4" "gopkg.in/src-d/go-billy.v4"
"gopkg.in/src-d/go-billy.v4/osfs" "gopkg.in/src-d/go-billy.v4/osfs"
@ -15,6 +14,7 @@ import (
"gopkg.in/src-d/go-git.v4/storage/filesystem" "gopkg.in/src-d/go-git.v4/storage/filesystem"
"opendev.org/airship/airshipctl/pkg/log" "opendev.org/airship/airshipctl/pkg/log"
"opendev.org/airship/airshipctl/pkg/util"
) )
var ( var (
@ -41,7 +41,7 @@ type Repository struct {
// NewRepository create repository object, with real filesystem on disk // NewRepository create repository object, with real filesystem on disk
// basePath is used to calculate final path where to clone/open the repository // basePath is used to calculate final path where to clone/open the repository
func NewRepository(basePath string, builder OptionsBuilder) (*Repository, error) { func NewRepository(basePath string, builder OptionsBuilder) (*Repository, error) {
dirName := nameFromURL(builder.URL()) dirName := util.GitDirNameFromURL(builder.URL())
if dirName == "" { if dirName == "" {
return nil, fmt.Errorf("URL: %s, original error: %w", builder.URL(), ErrCantParseURL) return nil, fmt.Errorf("URL: %s, original error: %w", builder.URL(), ErrCantParseURL)
} }
@ -60,11 +60,6 @@ func NewRepository(basePath string, builder OptionsBuilder) (*Repository, error)
}, nil }, nil
} }
func nameFromURL(urlString string) string {
_, fileName := filepath.Split(urlString)
return strings.TrimSuffix(fileName, ".git")
}
func storerFromFs(fs billy.Filesystem) (storage.Storer, error) { func storerFromFs(fs billy.Filesystem) (storage.Storer, error) {
dot, err := fs.Chroot(".git") dot, err := fs.Chroot(".git")
if err != nil { if err != nil {

View File

@ -38,19 +38,6 @@ func (md mockBuilder) ToFetchOptions(transport.AuthMethod) *git.FetchOptions {
} }
func (md mockBuilder) URL() string { return md.URLString } func (md mockBuilder) URL() string { return md.URLString }
func TestNewRepositoryNegative(t *testing.T) {
err := fixtures.Init()
require.NoError(t, err)
defer testutil.CleanUpGitFixtures(t)
builder := &mockBuilder{
URLString: "",
}
repo, err := NewRepository(".", builder)
assert.Error(t, err)
assert.Nil(t, repo)
}
func TestDownload(t *testing.T) { func TestDownload(t *testing.T) {
err := fixtures.Init() err := fixtures.Init()
require.NoError(t, err) require.NoError(t, err)
@ -216,47 +203,3 @@ func TestCheckout(t *testing.T) {
err = repo.Checkout(true) err = repo.Checkout(true)
assert.Error(t, err) assert.Error(t, err)
} }
func TestURLtoName(t *testing.T) {
tests := []struct {
input string
expectedOutput string
}{
{
input: "https://github.com/kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "git@github.com:kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "https://github.com/kubernetes/kube.somepath.ctl.git",
expectedOutput: "kube.somepath.ctl",
},
{
input: "https://github.com/kubernetes/kubectl",
expectedOutput: "kubectl",
},
{
input: "git@github.com:kubernetes/kubectl",
expectedOutput: "kubectl",
},
{
input: "github.com:kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "/kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "/kubernetes/kubectl.git/",
expectedOutput: "",
},
}
for _, test := range tests {
assert.Equal(t, test.expectedOutput, nameFromURL(test.input))
}
}

View File

@ -63,10 +63,6 @@ func getRemoteDirectClient(remoteConfig *config.RemoteDirect, remoteURL string)
func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.RemoteDirect, string, error) { func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.RemoteDirect, string, error) {
cfg := settings.Config() cfg := settings.Config()
manifest, err := cfg.CurrentContextManifest()
if err != nil {
return nil, "", err
}
bootstrapSettings, err := cfg.CurrentContextBootstrapInfo() bootstrapSettings, err := cfg.CurrentContextBootstrapInfo()
if err != nil { if err != nil {
return nil, "", err return nil, "", err
@ -77,14 +73,17 @@ func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.Re
return nil, "", config.ErrMissingConfig{What: "RemoteDirect options not defined in bootstrap config"} return nil, "", config.ErrMissingConfig{What: "RemoteDirect options not defined in bootstrap config"}
} }
// TODO (dukov) replace with the appropriate function once it's available root, err := cfg.CurrentContextEntryPoint(config.Ephemeral, "")
// in document module
docBundle, err := document.NewBundle(document.NewDocumentFs(), manifest.TargetPath, "")
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
ls := document.EphemeralClusterSelector docBundle, err := document.NewBundleByPath(root)
if err != nil {
return nil, "", err
}
ls := document.ControlNodeSelector
selector := document.NewSelector(). selector := document.NewSelector().
ByGvk("", "", AirshipHostKind). ByGvk("", "", AirshipHostKind).
ByLabel(ls) ByLabel(ls)

View File

@ -14,6 +14,7 @@ import (
) )
func initSettings(t *testing.T, rd *config.RemoteDirect, testdata string) *environment.AirshipCTLSettings { func initSettings(t *testing.T, rd *config.RemoteDirect, testdata string) *environment.AirshipCTLSettings {
t.Helper()
settings := &environment.AirshipCTLSettings{} settings := &environment.AirshipCTLSettings{}
settings.SetConfig(testutil.DummyConfig()) settings.SetConfig(testutil.DummyConfig())
bi, err := settings.Config().CurrentContextBootstrapInfo() bi, err := settings.Config().CurrentContextBootstrapInfo()
@ -36,7 +37,6 @@ func TestUnknownRemoteType(t *testing.T) {
) )
err := DoRemoteDirect(s) err := DoRemoteDirect(s)
_, ok := err.(*GenericError) _, ok := err.(*GenericError)
assert.True(t, ok) assert.True(t, ok)
} }
@ -52,7 +52,6 @@ func TestRedfishRemoteDirectWithEmptyURL(t *testing.T) {
) )
err := DoRemoteDirect(s) err := DoRemoteDirect(s)
_, ok := err.(redfish.ErrRedfishMissingConfig) _, ok := err.(redfish.ErrRedfishMissingConfig)
assert.True(t, ok) assert.True(t, ok)
} }

View File

@ -1,49 +0,0 @@
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/ephemeral: "true"
name: master-0
spec:
online: true
bootMACAddress: 00:3b:8b:0c:ec:8b
bmc:
address: redfish+http://nolocalhost:8888/redfish/v1/Systems/test-node
credentialsName: master-0-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/ephemeral: "true"
name: master-0-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/target: "true"
name: master-1
spec:
online: "true"
bootMACAddress: 01:3b:8b:0c:ec:8b
bmc:
address: ipmi://192.168.111.2:6230
credentialsName: master-1-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/target: "true"
name: master-1-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
...

View File

@ -0,0 +1,25 @@
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/node-role: "control-plane"
name: master-0
spec:
online: true
bootMACAddress: 00:3b:8b:0c:ec:8b
bmc:
address: redfish+http://nolocalhost:8888/redfish/v1/Systems/test-node
credentialsName: master-0-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/node-role: "control-plane"
name: master-0-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
...

View File

@ -1,49 +0,0 @@
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/ephemeral: "true"
name: master-0
spec:
online: true
bootMACAddress: 00:3b:8b:0c:ec:8b
bmc:
address: ""
credentialsName: master-0-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/ephemeral: "true"
name: master-0-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/target: "true"
name: master-1
spec:
online: true
bootMACAddress: 01:3b:8b:0c:ec:8b
bmc:
address: ipmi://192.168.111.2:6230
credentialsName: master-1-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/target: "true"
name: master-1-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
...

View File

@ -0,0 +1,25 @@
---
apiVersion: metal3.io/v1alpha1
kind: BareMetalHost
metadata:
labels:
airshipit.org/node-role: "control-plane"
name: master-0
spec:
online: true
bootMACAddress: 00:3b:8b:0c:ec:8b
bmc:
address: ""
credentialsName: master-0-bmc-secret
---
apiVersion: v1
kind: Secret
metadata:
labels:
airshipit.org/node-role: "control-plane"
name: master-0-bmc-secret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
...

12
pkg/util/url.go Normal file
View File

@ -0,0 +1,12 @@
package util
import (
"path/filepath"
"strings"
)
// GitDirNameFromURL extract directory name of the repository from URL
func GitDirNameFromURL(urlString string) string {
_, fileName := filepath.Split(urlString)
return strings.TrimSuffix(fileName, ".git")
}

51
pkg/util/url_test.go Normal file
View File

@ -0,0 +1,51 @@
package util
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGitDirNameFromURL(t *testing.T) {
tests := []struct {
input string
expectedOutput string
}{
{
input: "https://github.com/kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "git@github.com:kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "https://github.com/kubernetes/kube.somepath.ctl.git",
expectedOutput: "kube.somepath.ctl",
},
{
input: "https://github.com/kubernetes/kubectl",
expectedOutput: "kubectl",
},
{
input: "git@github.com:kubernetes/kubectl",
expectedOutput: "kubectl",
},
{
input: "github.com:kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "/kubernetes/kubectl.git",
expectedOutput: "kubectl",
},
{
input: "/kubernetes/kubectl.git/",
expectedOutput: "",
},
}
for _, test := range tests {
assert.Equal(t, test.expectedOutput, GitDirNameFromURL(test.input))
}
}

View File

@ -1,7 +1,6 @@
airship_config_action: generate airship_config_action: generate
airship_config_site_name: "test-bootstrap"
airship_config_iso_gen_target_path: "{{ serve_dir }}" airship_config_iso_gen_target_path: "{{ serve_dir }}"
airship_config_manifest_directory: "{{ remote_work_dir | default(zuul.project.src_dir) }}/manifests/site/{{ airship_config_site_name }}" airship_config_manifest_directory: "{{ remote_work_dir | default(zuul.project.src_dir) }}"
airship_config_ephemeral_ip: "{{ airship_gate_ipam.nat_network.ephemeral_ip }}" airship_config_ephemeral_ip: "{{ airship_gate_ipam.nat_network.ephemeral_ip }}"
airship_config_iso_builder_docker_image: "kkalynovskyi/image-builder:latest" airship_config_iso_builder_docker_image: "kkalynovskyi/image-builder:latest"
airship_config_ca_data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo= airship_config_ca_data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1USXlOakE0TWpneU5Gb1hEVEk1TVRJeU16QTRNamd5TkZvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTTFSClM0d3lnajNpU0JBZjlCR0JUS1p5VTFwYmdDaGQ2WTdJektaZWRoakM2K3k1ZEJpWm81ZUx6Z2tEc2gzOC9YQ1MKenFPS2V5cE5RcDN5QVlLdmJKSHg3ODZxSFZZNjg1ZDVYVDNaOHNyVVRzVDR5WmNzZHAzV3lHdDM0eXYzNi9BSQoxK1NlUFErdU5JemN6bzNEdWhXR0ZoQjk3VjZwRitFUTBlVWN5bk05c2hkL3AwWVFzWDR1ZlhxaENENVpzZnZUCnBka3UvTWkyWnVGUldUUUtNeGpqczV3Z2RBWnBsNnN0L2ZkbmZwd1Q5cC9WTjRuaXJnMEsxOURTSFFJTHVrU2MKb013bXNBeDJrZmxITWhPazg5S3FpMEloL2cyczRFYTRvWURZemt0Y2JRZ24wd0lqZ2dmdnVzM3pRbEczN2lwYQo4cVRzS2VmVGdkUjhnZkJDNUZNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFJek9BL00xWmRGUElzd2VoWjFuemJ0VFNURG4KRHMyVnhSV0VnclFFYzNSYmV3a1NkbTlBS3MwVGR0ZHdEbnBEL2tRYkNyS2xEeFF3RWg3NFZNSFZYYkFadDdsVwpCSm90T21xdXgxYThKYklDRTljR0FHRzFvS0g5R29jWERZY0JzOTA3ckxIdStpVzFnL0xVdG5hN1dSampqZnBLCnFGelFmOGdJUHZIM09BZ3B1RVVncUx5QU8ya0VnelZwTjZwQVJxSnZVRks2TUQ0YzFmMnlxWGxwNXhrN2dFSnIKUzQ4WmF6d0RmWUVmV3Jrdld1YWdvZ1M2SktvbjVEZ0Z1ZHhINXM2Snl6R3lPVnZ0eG1TY2FvOHNxaCs3UXkybgoyLzFVcU5ZK0hlN0x4d04rYkhwYkIxNUtIMTU5ZHNuS3BRbjRORG1jSTZrVnJ3MDVJMUg5ZGRBbGF0bz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=

View File

@ -1,8 +1,6 @@
airship_config_iso_gen_target_path: /srv/iso airship_config_iso_gen_target_path: /srv/iso
airship_config_manifest_directory: /tmp/airship airship_config_manifest_directory: /tmp/airship
airship_config_primary_repo_url: dummy.url.com airship_config_primary_repo_url: dummy.url.com
airship_config_primary_repo_auth_type: ssh-key
airship_config_primary_repo_key_path: ""
airship_config_ephemeral_ip: "10.23.25.101" airship_config_ephemeral_ip: "10.23.25.101"
airship_config_iso_builder_docker_image: quay.io/airshipit/isogen:latest airship_config_iso_builder_docker_image: quay.io/airshipit/isogen:latest
airship_config_iso_port: 8099 airship_config_iso_port: 8099

View File

@ -13,16 +13,19 @@ current-context: dummy_cluster
kind: Config kind: Config
manifests: manifests:
dummy_manifest: dummy_manifest:
repository: primary-repository: primary
auth: repositories:
ssh-key: {{ airship_config_primary_repo_key_path | default("") }} primary:
type: {{ airship_config_primary_repo_auth_type }} checkout:
checkout: branch: "master"
branch: "master" force: false
force: false remote-ref: ""
remote-ref: "" tag: ""
tag: "" url: {{ airship_config_primary_repo_url }}
url: {{ airship_config_primary_repo_url }} ## this is temporary hack, as soon as we use `document pull` command in gate process
## this will subpath will be airshipctl/manifests/site/test-bootstrap, as airshipctl
## will be primary repository
sub-path: "manifests/site/test-bootstrap"
target-path: {{ airship_config_manifest_directory }} target-path: {{ airship_config_manifest_directory }}
modules-config: modules-config:
bootstrapInfo: bootstrapInfo:

View File

@ -90,15 +90,17 @@ func DummyCluster() *config.Cluster {
func DummyManifest() *config.Manifest { func DummyManifest() *config.Manifest {
m := config.NewManifest() m := config.NewManifest()
// Repositories is the map of repository adddressable by a name // Repositories is the map of repository adddressable by a name
m.Repository = DummyRepository() m.Repositories = map[string]*config.Repository{"primary": DummyRepository()}
m.PrimaryRepositoryName = "primary"
m.TargetPath = "/var/tmp/" m.TargetPath = "/var/tmp/"
m.SubPath = "manifests/site/test-site"
return m return m
} }
// DummyRepository, utility function used for tests // DummyRepository, utility function used for tests
func DummyRepository() *config.Repository { func DummyRepository() *config.Repository {
return &config.Repository{ return &config.Repository{
URLString: "http://dummy.url.com", URLString: "http://dummy.url.com/manifests.git",
CheckoutOptions: &config.RepoCheckout{ CheckoutOptions: &config.RepoCheckout{
Tag: "v1.0.1", Tag: "v1.0.1",
ForceCheckout: false, ForceCheckout: false,