-
-
Notifications
You must be signed in to change notification settings - Fork 582
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
"ddev list" shows sites based on container, even if directory is removed: fix for #374 #444
Conversation
pkg/plugins/platform/utils.go
Outdated
tempConfig.Name = siteContainer.Labels["com.ddev.site-name"] | ||
tempSite := &LocalApp{tempConfig} | ||
apps[platformType] = append(apps[platformType], tempSite) | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This break feels kind of weird? what are we breaking from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This break stops the site
variable from running .Init(<app_root>)
a few lines below
pkg/plugins/platform/utils.go
Outdated
@@ -197,3 +210,15 @@ func ddevContainersRunning() (bool, error) { | |||
} | |||
return false, nil | |||
} | |||
|
|||
// exists returns whether the given file or directory exists or not | |||
func exists(path string) (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the FileExists from our fileutils package: https://github.com/drud/ddev/blob/master/pkg/fileutil/files.go#L119
It's already imported here, so it should be an easy update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ran through this and it looks like it breaks some existing functionality.
Here's what I did
- Started two sites. "drudio" and "ddevd7"
- Run a
ddev list
(master) to ensure both were shown in the output - Deleted the "drudio" folder.
- Run
ddev list
. Observed only a "ddevd7" site. - Compile this PR. Run
ddev list
. Observered only "drudio" listed. It showed the deleted folder "~/Projects/testing/drudio" - Checked out master again
- Run
ddev list
on master. Observed only "ddevd7" listed.
tl;dr: When a site is deleted it appears that this PR only shows the deleted site. Or perhaps just the first site.
Console output:
drudapi/docker.nginx-php-fpm-hosting git:(master) ✗ » ddev list
2 local sites found.
NAME TYPE LOCATION URL STATUS
drudio wordpress ~/Projects/testing/drudio http://drudio.ddev.local running
ddevd7 drupal7 ~/Projects/ddev/ddevd7 http://ddevd7.ddev.local running
DDEV ROUTER STATUS: running
drudapi/docker.nginx-php-fpm-hosting git:(master) ✗ » z ddev
drud/ddev git:(nginx-tag) » hub checkout https://github.com/drud/ddev/pull/444/files
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 12 (delta 6), reused 12 (delta 6), pack-reused 0
Unpacking objects: 100% (12/12), done.
From git://github.com/nmccrory/ddev
* [new branch] ddev-list-rmdir -> nmccrory/ddev-list-rmdir
Branch nmccrory-ddev-list-rmdir set up to track remote branch ddev-list-rmdir from nmccrory.
Switched to a new branch 'nmccrory-ddev-list-rmdir'
drud/ddev git:(nmccrory-ddev-list-rmdir) » rm -rf ~/Projects/testing/drudio
drud/ddev git:(nmccrory-ddev-list-rmdir) » ddev list
1 local site found.
NAME TYPE LOCATION URL STATUS
ddevd7 drupal7 ~/Projects/ddev/ddevd7 http://ddevd7.ddev.local running
DDEV ROUTER STATUS: running
drud/ddev git:(nmccrory-ddev-list-rmdir) » make darwin
building darwin from ./cmd/... ./pkg/...
drud/ddev git:(nmccrory-ddev-list-rmdir) » ddev list
1 local site found.
NAME TYPE LOCATION URL STATUS
drudio ~/Projects/testing/drudio http://drudio.ddev.local web service unhealthy
DDEV ROUTER STATUS: running
drud/ddev git:(nmccrory-ddev-list-rmdir) » git checkout master
drud/ddev git:(master) » make darwin
building darwin from ./cmd/... ./pkg/...
drud/ddev git:(master) » ddev list
1 local site found.
NAME TYPE LOCATION URL STATUS
ddevd7 drupal7 ~/Projects/ddev/ddevd7 http://ddevd7.ddev.local running
Thanks for testing this and giving your feedback @beeradb. I'll investigate into what's causing the issue (maybe the break statement as you mentioned above). |
@nmccrory @beeradb I've followed the conversation in our team Slack channel. I believe the summarized approach is that ddev list should still show containers that persist even when the directory has been removed. However, there are two possible scenarios:
In both cases, we should probably note the issue in the status column and (at the bottom of the ddev list output) provide instructions how to either resolve OR remove the containers. Is that the summarized proposal? Right now, the PR summary mentions a status of "not found", but it doesn't indicate what instructions or helper text would be provided to help resolve the detached containers. |
If you could just push a dummy commit into this it should pass surf-windows @nmccrory |
@nmccrory could you comment on why this couldn't be handled in the status field, the same as what happens when a particular service hasn't come up or has been disabled? I know you explored that, just don't understand why it didn't work out. |
adfb4ee
to
2f231bd
Compare
pkg/plugins/platform/types.go
Outdated
@@ -46,7 +49,7 @@ var PluginMap = map[string]App{ | |||
} | |||
|
|||
// GetPluginApp will return an application of the type specified by pluginType | |||
func GetPluginApp(pluginType string) (App, error) { | |||
func GetPluginApp(pluginType string) (*LocalApp, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider this piece rather heavily. This works best now because it is the only way I could add the InitFromMissingDirectory(string, string)
method on type LocalApp
, without defining it as a required part of the App
interface.
In the future, if we deal with other App
types that are not LocalApp
we would need to revert to returning the App
generic. Right now however, the only possible return value is LocalApp
. I'm not sure what our long term plans are or if there are situations where this may not be the case. Can definitely use feedback here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say don't do it and don't bother with adding the InitFromMissingDirectory(), as elsewhere.
This PR is ready for review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor changes requested - Just lose the extra function and do those 2 lines inline. Add some comments, etc.
- You probably need to test the other commands. For example,
ddev describe TestMainPkgWordpress
doesn't work here, neither doesddev rm TestMainPkgWordpress
orddev stop TestMainPkgWordpress
orddev logs TestMainPkgWordpress
, which people will want. Maybe should also be fixed at this time? My bet is they're pretty easy given what you've already learned. Probably it just means adding your general approach to those. Or maybe they can't be done. I'm ok if it's impossible, but it would be nice to see the general case solved.
pkg/plugins/platform/utils.go
Outdated
if err != nil { | ||
siteName := siteContainer.Labels["com.ddev.site-name"] | ||
appType := siteContainer.Labels["com.ddev.app-type"] | ||
site.InitFromMissingDirectory(siteName, appType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's worth adding the function here. There are only 2 lines in the function, and it probably has a misleading name. So
- just take those 2 lines and put them here.
- Add a comment for this stanza saying what the situation is.
- Also, make sure there aren't other reasons that the site.Init() might fail that would cause misbehavior in this stanza. (Like do we have a siteContainer OK?)
I'm just saying do this:
if err != nil {
siteName := siteContainer.Labels["com.ddev.site-name"]
appType := siteContainer.Labels["com.ddev.app-type"]
site.AppConfig.Name = siteName
site.AppConfig.AppType = appType
log.Printf("Failed to init %v err=%v", approot, err)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately in this case, we can't access the site's AppConfig from this context. This has something to do with the way we are using the App interface, but regardless we need to brainstorm because I agree that it should not have to be its own function...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brainstorm successful: we can work around this situation by casting site
as type LocalApp
. From there you can edit values in .AppConfig
.
pkg/plugins/platform/local.go
Outdated
@@ -47,6 +47,7 @@ func (l *LocalApp) GetType() string { | |||
func (l *LocalApp) Init(basePath string) error { | |||
config, err := ddevapp.NewConfig(basePath, "") | |||
if err != nil { | |||
l.AppConfig = config |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment above this saying why we're saving it away, so somebody doesn't remove this someday.
pkg/plugins/platform/types.go
Outdated
@@ -46,7 +49,7 @@ var PluginMap = map[string]App{ | |||
} | |||
|
|||
// GetPluginApp will return an application of the type specified by pluginType | |||
func GetPluginApp(pluginType string) (App, error) { | |||
func GetPluginApp(pluginType string) (*LocalApp, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say don't do it and don't bother with adding the InitFromMissingDirectory(), as elsewhere.
…xt to our changes using comments.
2f231bd
to
e3c5544
Compare
@rfay Ready for review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is ready, please make the one fix I requested. I don't care about the variable name as long as it doesn't shadow "site".
pkg/plugins/platform/utils.go
Outdated
apps[platformType] = append(apps[platformType], site) | ||
if err != nil { | ||
// Cast 'site' from type App to type LocalApp, so we can manually enter AppConfig values. | ||
site := site.(*LocalApp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast returns 2 args, the struct (if it exists) and "ok" that tells you whether it existed. I'd rather see
siteStruct, ok := site.(*LocalApp)
if (ok) {
siteStruct.AppConfig.Name = siteName
siteStruct.AppConfig.AppType = appType
}
There are two issues here:
- Catch the case where the cast doesn't work (unlikely, but defensive code is good)
- Don't change the meaning of the variable "site" in the middle of the code. It was one thing, and changing it to something completely different could throw somebody working on this in the future. Never forget that this has a life after you work on it.
…iable storing the casted value.
Requested changes have been made. Thanks for your feedback, Randy! @rfay |
pkg/plugins/platform/utils.go
Outdated
// Cast 'site' from type App to type LocalApp, so we can manually enter AppConfig values. | ||
siteStruct, ok := site.(*LocalApp) | ||
if !ok { | ||
log.Fatalf("Failed to init %v err=%v", approot, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't mind the path you took here, but the error message makes no sense. Please make it make sense. It needs to be about the failure of the cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this context I feel we would want this error to be the one presented. It is more important than the failure to cast because casting only happens when we can't find a config in the app's root directory. If we can't resolve the missing directory issue by casting, we want to return the overall error that the cast is nested in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think presenting the failure to cast message on the line before the log.Fatalf
would be a good compromise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really close. I think we need one more conditional to check for the absence of a ddev config as well. My original testing method was just to move my .ddev folder after starting, and no errors were reported.
If we can get that other check in place I think we'll be 👍
@@ -266,6 +268,10 @@ func (l *LocalApp) SiteStatus() string { | |||
var siteStatus string | |||
services := map[string]string{"web": "", "db": ""} | |||
|
|||
if !fileutil.FileExists(l.AppRoot()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only notifies a user if the entire AppRoot
is missing. The case where just a .ddev/config.yaml
file is missing is also an issue. It would be great to add another check here (and error return) if the config can't be found.
@beeradb - your feedback has been incorporated. |
@beeradb if you're good with this we should let him get it in because the followup work uses some of these things. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This worked as expected for me:
drud/ddev ‹minikube› git:(nmccrory-ddev-list-rmdir) » ddev list
1 local site found.
NAME TYPE LOCATION URL STATUS
d7kickstart drupal7 ~/Projects/testing/d7kickstart http://d7kickstart.ddev.local .ddev/config.yml missing
I would note that a full path would probably be preferable under status, but I don't see a need to hold this up for that. It might be nice to add the full path to the output in one of the follow-ups to this, though.
Thanks so much for the work on this. Here's a baloon🎈
The Problem:
A reoccurring issue in
ddev list
was its failure to list sites whose directories had been removed but containers were still running. This pitfall inddev list
made it possible for containers (which were no longer useful) to heap up on a user's machine if they repeatedly removed sites usingrm -r <dir>
instead ofddev rm
- which stops all containers associated with a particular site.The Fix:
TLDR; check to see if a site's root directory exists. If it doesn't exist, store information about the site temporarily and list it with status "not found".
ddev list
already had visibility into the ddev containers that were running on a machine, it simply would not include sites with missing directories because those sites would raise an error when attempting to initialize from a missing rootsite.Init(<root_dir>)
.The Test:
ddev list
thendocker ps
Related Issue Link(s):
#374