Skip to content
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
205 changes: 98 additions & 107 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,148 +399,139 @@ func (cmd *InitCmd) configureKubernetes() {

func (cmd *InitCmd) configureRegistry() {
internalRegistryConfig := cmd.config.Services.InternalRegistry

enableAutomaticBuilds := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "Do you want to enable automatic Docker image building?",
createInternalRegistry := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "Should we create a private registry within your Kubernetes cluster for you? (yes | no)",
DefaultValue: "yes",
ValidationRegexPattern: "^(yes)|(no)$",
})

if *enableAutomaticBuilds == "yes" {
internalRegistryKey := "internal registry"
defaultRegistryValue := internalRegistryKey

if cmd.defaultRegistry.URL != nil {
defaultRegistryValue = *cmd.defaultRegistry.URL
}
if *createInternalRegistry == "no" {
registryURL := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "Which registry do you want to push to? ('internal registry', 'hub.docker.com' or URL)",
DefaultValue: defaultRegistryValue,
Question: "Which registry do you want to push to? ('hub.docker.com' or URL)",
DefaultValue: "hub.docker.com",
ValidationRegexPattern: "^.*$",
})

if *registryURL != internalRegistryKey {
cmd.defaultRegistry.URL = registryURL
internalRegistryConfig = nil
cmd.defaultRegistry.URL = registryURL
internalRegistryConfig = nil

if *registryURL == "hub.docker.com" {
defaultImageName := *cmd.defaultImage.Name
defaultImageNameParts := strings.Split(defaultImageName, "/")
existingDockerUsername := ""

if len(defaultImageNameParts) > 1 {
existingDockerUsername = defaultImageNameParts[0]
}
if *registryURL == "hub.docker.com" {
defaultImageName := *cmd.defaultImage.Name
defaultImageNameParts := strings.Split(defaultImageName, "/")
existingDockerUsername := ""

dockerUsername := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "What is your Docker username?",
DefaultValue: existingDockerUsername,
ValidationRegexPattern: "^[a-zA-Z0-9]{4,30}$",
})
cmd.defaultImage.Name = configutil.String(*dockerUsername + "/" + strings.TrimPrefix(defaultImageName, *dockerUsername))
if len(defaultImageNameParts) > 1 {
existingDockerUsername = defaultImageNameParts[0]
}
} else {
imageMap := *cmd.config.Images
defaultImageConf, defaultImageExists := imageMap["default"]

if defaultImageExists {
defaultImageConf.Registry = configutil.String("internal")
}
dockerUsername := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "What is your Docker username?",
DefaultValue: existingDockerUsername,
ValidationRegexPattern: "^[a-zA-Z0-9]{4,30}$",
})
cmd.defaultImage.Name = configutil.String(*dockerUsername + "/" + strings.TrimPrefix(defaultImageName, *dockerUsername))
}
} else {
imageMap := *cmd.config.Images
defaultImageConf, defaultImageExists := imageMap["default"]

if internalRegistryConfig == nil {
internalRegistryConfig = &v1.InternalRegistry{
Release: &v1.Release{},
}
cmd.config.Services.InternalRegistry = internalRegistryConfig
}
if defaultImageExists {
defaultImageConf.Registry = configutil.String("internal")
}

if internalRegistryConfig.Release.Name == nil {
internalRegistryConfig.Release.Name = configutil.String("devspace-registry")
if internalRegistryConfig == nil {
internalRegistryConfig = &v1.InternalRegistry{
Release: &v1.Release{},
}
cmd.config.Services.InternalRegistry = internalRegistryConfig
}

if internalRegistryConfig.Release.Namespace == nil {
internalRegistryConfig.Release.Namespace = cmd.config.DevSpace.Release.Namespace
}
overwriteRegistryMap := *cmd.overwriteConfig.Registries
if internalRegistryConfig.Release.Name == nil {
internalRegistryConfig.Release.Name = configutil.String("devspace-registry")
}

overwriteRegistryConfig, overwriteRegistryConfigFound := overwriteRegistryMap["internal"]
if internalRegistryConfig.Release.Namespace == nil {
internalRegistryConfig.Release.Namespace = cmd.config.DevSpace.Release.Namespace
}
overwriteRegistryMap := *cmd.overwriteConfig.Registries

if !overwriteRegistryConfigFound {
overwriteRegistryConfig = &v1.RegistryConfig{
Auth: &v1.RegistryAuth{},
}
overwriteRegistryMap["internal"] = overwriteRegistryConfig
overwriteRegistryConfig, overwriteRegistryConfigFound := overwriteRegistryMap["internal"]

if !overwriteRegistryConfigFound {
overwriteRegistryConfig = &v1.RegistryConfig{
Auth: &v1.RegistryAuth{},
}
registryAuth := overwriteRegistryConfig.Auth
overwriteRegistryMap["internal"] = overwriteRegistryConfig
}
registryAuth := overwriteRegistryConfig.Auth

if registryAuth.Username == nil {
randomUserSuffix, err := randutil.GenerateRandomString(5)
if registryAuth.Username == nil {
randomUserSuffix, err := randutil.GenerateRandomString(5)

if err != nil {
log.Fatalf("Error creating random username: %s", err.Error())
}
registryAuth.Username = configutil.String("user-" + randomUserSuffix)
if err != nil {
log.Fatalf("Error creating random username: %s", err.Error())
}
registryAuth.Username = configutil.String("user-" + randomUserSuffix)
}

if registryAuth.Password == nil {
randomPassword, err := randutil.GenerateRandomString(12)
if registryAuth.Password == nil {
randomPassword, err := randutil.GenerateRandomString(12)

if err != nil {
log.Fatalf("Error creating random password: %s", err.Error())
}
registryAuth.Password = &randomPassword
if err != nil {
log.Fatalf("Error creating random password: %s", err.Error())
}
var registryReleaseValues map[interface{}]interface{}

if internalRegistryConfig.Release.Values != nil {
registryReleaseValues = *internalRegistryConfig.Release.Values
} else {
registryReleaseValues = map[interface{}]interface{}{}

registryDomain := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "Which domain should your container registry be using? (optional, requires an ingress controller)",
ValidationRegexPattern: "^(([a-z0-9]([a-z0-9-]{0,120}[a-z0-9])?\\.)+[a-z0-9]{2,})?$",
})

if *registryDomain != "" {
registryReleaseValues = map[interface{}]interface{}{
"Ingress": map[string]interface{}{
"Enabled": true,
"Hosts": []string{
*registryDomain,
},
"Annotations": map[string]string{
"Kubernetes.io/tls-acme": "true",
},
"Tls": []map[string]interface{}{
map[string]interface{}{
"SecretName": "tls-devspace-registry",
"Hosts": []string{
*registryDomain,
},
registryAuth.Password = &randomPassword
}
var registryReleaseValues map[interface{}]interface{}

if internalRegistryConfig.Release.Values != nil {
registryReleaseValues = *internalRegistryConfig.Release.Values
} else {
registryReleaseValues = map[interface{}]interface{}{}

registryDomain := stdinutil.GetFromStdin(&stdinutil.GetFromStdinParams{
Question: "Which domain should your container registry be using? (optional, requires an ingress controller)",
ValidationRegexPattern: "^(([a-z0-9]([a-z0-9-]{0,120}[a-z0-9])?\\.)+[a-z0-9]{2,})?$",
})

if *registryDomain != "" {
registryReleaseValues = map[interface{}]interface{}{
"Ingress": map[string]interface{}{
"Enabled": true,
"Hosts": []string{
*registryDomain,
},
"Annotations": map[string]string{
"Kubernetes.io/tls-acme": "true",
},
"Tls": []map[string]interface{}{
map[string]interface{}{
"SecretName": "tls-devspace-registry",
"Hosts": []string{
*registryDomain,
},
},
},
}
},
}
}
secrets, registryHasSecrets := registryReleaseValues["secrets"]
}
secrets, registryHasSecrets := registryReleaseValues["secrets"]

if !registryHasSecrets {
secrets = map[interface{}]interface{}{}
registryReleaseValues["secrets"] = secrets
}
secretMap, secretsIsMap := secrets.(map[interface{}]interface{})
if !registryHasSecrets {
secrets = map[interface{}]interface{}{}
registryReleaseValues["secrets"] = secrets
}
secretMap, secretsIsMap := secrets.(map[interface{}]interface{})

if secretsIsMap {
_, registryHasSecretHtpasswd := secretMap["htpasswd"]
if secretsIsMap {
_, registryHasSecretHtpasswd := secretMap["htpasswd"]

if !registryHasSecretHtpasswd {
secretMap["htpasswd"] = ""
}
if !registryHasSecretHtpasswd {
secretMap["htpasswd"] = ""
}
internalRegistryConfig.Release.Values = &registryReleaseValues
}
internalRegistryConfig.Release.Values = &registryReleaseValues
}
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (cmd *UpCmd) Run(cobraCmd *cobra.Command, args []string) {
if cmd.flags.initRegistries {
cmd.initRegistries()
}
mustRedeploy := cmd.flags.deploy
mustRedeploy := false

if cmd.flags.build {
mustRedeploy = cmd.buildImages(cobraCmd.Flags().Changed("build"))
Expand All @@ -150,7 +150,7 @@ func (cmd *UpCmd) Run(cobraCmd *cobra.Command, args []string) {
// Check if we find a running release pod
pod, err := getRunningDevSpacePod(cmd.helm, cmd.kubectl)

if err != nil || mustRedeploy {
if err != nil || mustRedeploy || cmd.flags.deploy {
cmd.deployChart()
} else {
cmd.pod = pod
Expand Down
18 changes: 15 additions & 3 deletions pkg/devspace/sync/evaluater.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ func shouldUpload(relativePath string, stat os.FileInfo, s *SyncConfig, isInitia

if isInitial {
// File is older locally than remote so don't update remote
if ceilMtime(stat.ModTime()) <= s.fileIndex.fileMap[relativePath].Mtime+1 {
if roundMtime(stat.ModTime()) <= s.fileIndex.fileMap[relativePath].Mtime {
return false
}
} else {
// File did not change or was changed by downstream
if ceilMtime(stat.ModTime()) == s.fileIndex.fileMap[relativePath].Mtime && stat.Size() == s.fileIndex.fileMap[relativePath].Size {
if roundMtime(stat.ModTime()) == s.fileIndex.fileMap[relativePath].Mtime && stat.Size() == s.fileIndex.fileMap[relativePath].Size {
return false
}
}
Expand Down Expand Up @@ -140,35 +140,47 @@ func shouldDownload(fileInformation *fileInformation, s *SyncConfig) bool {
// - The file is present on the filesystem and did not change in terms of size and mtime on the filesystem
func shouldRemoveLocal(absFilepath string, fileInformation *fileInformation, s *SyncConfig) bool {
if fileInformation == nil {
s.Logf("Skip %s because fileInformation is nil", absFilepath)
return false
}

// We don't need to check s.ignoreMatcher, because if a path is ignored it will never be added to the fileMap, because shouldDownload
// and shouldUpload are always false, and hence it never appears in the fileMap and is not copied to the remove fileMap clone
// in the beginning of the downstream mainLoop

// Exclude files on the exclude list
if s.downloadIgnoreMatcher != nil {
if s.downloadIgnoreMatcher.MatchesPath(fileInformation.Name) {
s.Logf("Skip %s because downloadIgnoreMatcher matched", absFilepath)
return false
}
}

// Only delete if mtime and size did not change
stat, err := os.Stat(absFilepath)
if err != nil {
s.Logf("Skip %s because stat returned %v", absFilepath, stat)
return false
}

// We don't delete the file if we haven't tracked it
if stat != nil && s.fileIndex.fileMap[fileInformation.Name] != nil {
if stat.IsDir() != s.fileIndex.fileMap[fileInformation.Name].IsDirectory || stat.IsDir() != fileInformation.IsDirectory {
s.Logf("Skip %s because stat returned unequal isdir with fileMap", absFilepath)
return false
}

if fileInformation.IsDirectory == false {
// We don't delete the file if it has changed in the map since we collected changes
if fileInformation.Mtime == s.fileIndex.fileMap[fileInformation.Name].Mtime && fileInformation.Size == s.fileIndex.fileMap[fileInformation.Name].Size {
// We don't delete the file if it has changed on the filesystem meanwhile
if ceilMtime(stat.ModTime()) <= fileInformation.Mtime {
if roundMtime(stat.ModTime()) <= fileInformation.Mtime {
return true
}

s.Logf("Skip %s because stat.ModTime() %d is greater than fileInformation.Mtime %d", absFilepath, roundMtime(stat.ModTime()), fileInformation.Mtime)
} else {
s.Logf("Skip %s because Mtime (%d and %d) or Size (%d and %d) is unequal between fileInformation and fileMap", absFilepath, fileInformation.Mtime, s.fileIndex.fileMap[fileInformation.Name].Mtime, fileInformation.Size, s.fileIndex.fileMap[fileInformation.Name].Size)
}
} else {
return true
Expand Down
8 changes: 4 additions & 4 deletions pkg/devspace/sync/sync_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,11 @@ func (s *SyncConfig) diffServerClient(filepath string, sendChanges *[]*fileInfor
if s.uploadIgnoreMatcher.MatchesPath(relativePath) {
s.fileIndex.fileMapMutex.Lock()
// Add to file map and prevent download if local file is newer than the remote one
if s.fileIndex.fileMap[relativePath] != nil && s.fileIndex.fileMap[relativePath].Mtime < ceilMtime(stat.ModTime()) {
if s.fileIndex.fileMap[relativePath] != nil && s.fileIndex.fileMap[relativePath].Mtime < roundMtime(stat.ModTime()) {
// Add it to the fileMap
s.fileIndex.fileMap[relativePath] = &fileInformation{
Name: relativePath,
Mtime: ceilMtime(stat.ModTime()),
Mtime: roundMtime(stat.ModTime()),
Size: stat.Size(),
IsDirectory: stat.IsDir(),
}
Expand All @@ -338,7 +338,7 @@ func (s *SyncConfig) diffServerClient(filepath string, sendChanges *[]*fileInfor
// Add file to upload
*sendChanges = append(*sendChanges, &fileInformation{
Name: relativePath,
Mtime: ceilMtime(stat.ModTime()),
Mtime: roundMtime(stat.ModTime()),
Size: stat.Size(),
IsDirectory: false,
})
Expand All @@ -358,7 +358,7 @@ func (s *SyncConfig) diffDir(filepath string, stat os.FileInfo, sendChanges *[]*
if len(files) == 0 && relativePath != "" {
*sendChanges = append(*sendChanges, &fileInformation{
Name: relativePath,
Mtime: ceilMtime(stat.ModTime()),
Mtime: roundMtime(stat.ModTime()),
Size: stat.Size(),
IsDirectory: true,
})
Expand Down
18 changes: 0 additions & 18 deletions pkg/devspace/sync/sync_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,21 +611,3 @@ func TestRemoveDirInFileMap(t *testing.T) {
t.Fail()
}
}

func TestCeilMtime(t *testing.T) {
ceiledNumberNano := time.Unix(1533647574, 0)
ceiledNumberSeconds := time.Unix(1533647574, 0)

unceiledNumberNano := time.Unix(1533647574, 1)
unceiledNumberSeconds := time.Unix(1533647575, 0)

if ceilMtime(ceiledNumberNano) != ceiledNumberSeconds.Unix() {
t.Error("ceilMtime failed ceiledNumberNano != ceiledNumberSeconds")
t.Fail()
}

if ceilMtime(unceiledNumberNano) != unceiledNumberSeconds.Unix() {
t.Error("ceilMtime failed unceiledNumberNano != unceiledNumberSeconds")
t.Fail()
}
}
Loading