yesodweb / yesod

A RESTful Haskell web framework built on WAI.
http://www.yesodweb.com/
MIT License
2.64k stars 374 forks source link

Quick start guide does not work #1517

Closed rszibele closed 6 years ago

rszibele commented 6 years ago

Following the quick start guide at https://www.yesodweb.com/page/quickstart I can't seem to get yesod-sqlite to work. Everything builds fine but it seems that the executable exits early, thereby only displaying the page with "The application isn't built".

e.g:

richard@linux-aovt:~/Documents/szibele> stack exec -- yesod devel
Yesod devel server. Enter 'quit' or hit Ctrl-C to quit.
Application can be accessed at:

http://localhost:3000
https://localhost:3443
If you wish to test https capabilities, you should set the following variable:
export APPROOT=https://localhost:3443

ExitSuccess
Type help for available commands. Press enter to force a rebuild.
Starting devel application
Devel application launched: http://localhost:3000

What makes me suspicious is the ExitSuccess line.

My setup:

operating system: OpenSUSE Leap 15

richard@linux-aovt:~> uname
Linux

richard@linux-aovt:~> uname -a
Linux linux-aovt 4.17.0-1.gbcb3422-vanilla #1 SMP PREEMPT Mon Jun 4 08:26:32 UTC 2018 (bcb3422) x86_64 x86_64 x86_64 GNU/Linux

richard@linux-aovt:~> stack --version
Version 1.7.1, Git revision 681c800873816c022739ca7ed14755e85a579565 (5807 commits) x86_64 hpack-0.28.2

richard@linux-aovt:~> stack ghc -- --version
Writing implicit global project config file to: /home/richard/.stack/global-project/stack.yaml
Note: You can change the snapshot via the resolver field there.
Using latest snapshot resolver: lts-11.12
The Glorious Glasgow Haskell Compilation System, version 8.2.2

richard@linux-aovt:~/Documents/szibele> stack list-dependencies
DEPRECATED: Use ls dependencies instead. Will be removed in next major version.
Cabal 2.0.1.1
StateVar 1.1.1.0
adjunctions 4.4
aeson 1.2.4.0
aeson-compat 0.3.7.1
ansi-terminal 0.8.0.4
ansi-wl-pprint 0.6.8.2
appar 0.1.4
array 0.5.2.0
asn1-encoding 0.9.5
asn1-parse 0.9.4
asn1-types 0.3.2
async 2.1.1.1
attoparsec 0.13.2.2
attoparsec-iso8601 1.0.0.0
authenticate 1.3.4
auto-update 0.1.4
base 4.10.1.0
base-compat 0.9.3
base-orphans 0.7
base16-bytestring 0.1.1.6
base64-bytestring 1.0.0.1
basement 0.0.7
basic-prelude 0.7.0
bifunctors 5.5.2
binary 0.8.5.1
blaze-builder 0.4.1.0
blaze-html 0.9.0.1
blaze-markup 0.8.2.1
bsb-http-chunked 0.0.0.2
byteable 0.1.1
byteorder 1.0.4
bytestring 0.10.8.2
bytestring-builder 0.10.8.1.0
cabal-doctest 1.0.6
case-insensitive 1.2.0.11
cereal 0.5.5.0
chunked-data 0.3.1
cipher-aes 0.2.11
classy-prelude 1.4.0
classy-prelude-conduit 1.4.0
classy-prelude-yesod 1.4.0
clientsession 0.9.1.2
colour 2.3.4
comonad 5.0.3
conduit 1.3.0.2
conduit-extra 1.3.0
connection 0.2.8
containers 0.5.10.2
contravariant 1.4.1
cookie 0.4.4
cpphs 1.20.8
cprng-aes 0.6.1
crypto-api 0.13.3
crypto-cipher-types 0.0.9
crypto-random 0.0.9
cryptonite 0.25
cryptonite-conduit 0.2.2
css-text 0.1.3.0
data-default 0.7.1.1
data-default-class 0.1.2.0
data-default-instances-containers 0.0.1
data-default-instances-dlist 0.0.1
data-default-instances-old-locale 0.0.1
deepseq 1.4.3.0
deepseq-generics 0.2.0.0
directory 1.3.0.2
distributive 0.5.3
dlist 0.8.0.4
dlist-instances 0.1.1.1
easy-file 0.2.2
email-validate 2.3.2.5
entropy 0.3.8
exceptions 0.8.3
fail 4.9.0.0
fast-logger 2.4.11
file-embed 0.0.10.1
filepath 1.4.1.2
foreign-store 0.2
foundation 0.0.20
free 5.0.2
ghc-boot-th 8.2.2
ghc-prim 0.5.1.1
hashable 1.2.7.0
haskell-src-exts 1.20.2
haskell-src-meta 0.8.0.2
hjsmin 0.2.0.2
hourglass 0.2.11
http-api-data 0.3.7.2
http-client 0.5.12.1
http-client-tls 0.3.5.3
http-conduit 2.3.1
http-date 0.0.7
http-types 0.12.1
http2 1.6.3
integer-gmp 1.0.1.0
integer-logarithms 1.0.2.1
iproute 1.7.5
kan-extensions 5.1
keys 3.12
language-javascript 0.6.0.11
lifted-base 0.2.3.12
memory 0.14.16
microlens 0.4.8.3
microlens-th 0.4.1.3
mime-mail 0.4.14
mime-types 0.1.0.7
monad-control 1.0.2.3
monad-logger 0.3.28.5
monad-loops 0.4.3
mono-traversable 1.0.8.1
mono-traversable-instances 0.1.0.0
mtl 2.2.2
mutable-containers 0.3.4
network 2.6.3.5
network-uri 2.6.1.0
nonce 1.0.7
old-locale 1.0.0.7
old-time 1.1.0.3
optparse-applicative 0.14.2.0
parsec 3.1.13.0
path-pieces 0.2.1
pem 0.2.4
persistent 2.8.2
persistent-sqlite 2.8.1.2
persistent-template 2.5.4
pointed 5.0.1
polyparse 1.12
pretty 1.1.3.3
primitive 0.6.3.0
process 1.6.1.0
profunctors 5.2.2
psqueues 0.2.7.0
random 1.1
resource-pool 0.2.3.2
resourcet 1.2.1
rts 1.0
safe 0.3.17
say 0.1.0.0
scientific 0.3.6.2
securemem 0.1.10
semigroupoids 5.2.2
semigroups 0.18.4
setenv 0.1.1.3
shakespeare 2.0.15
silently 1.2.5
simple-sendfile 0.2.27
skein 1.0.9.4
socks 0.5.6
split 0.2.3.3
stm 2.4.5.0
stm-chans 3.0.0.4
streaming-commons 0.1.19
stringsearch 0.3.6.6
syb 0.7
szibele 0.0.0
tagged 0.8.5
tagsoup 0.14.6
tagstream-conduit 0.5.5.3
template-haskell 2.12.0.0
text 1.2.3.0
th-abstraction 0.2.6.0
th-expand-syns 0.4.4.0
th-lift 0.7.10
th-lift-instances 0.1.11
th-orphans 0.13.5
th-reify-many 0.1.8
time 1.8.0.2
time-locale-compat 0.1.1.4
tls 1.4.1
transformers 0.5.2.0
transformers-base 0.4.4
transformers-compat 0.5.1.4
typed-process 0.2.2.0
unix 2.7.2.2
unix-compat 0.5.0.1
unix-time 0.3.8
unliftio 0.2.7.0
unliftio-core 0.1.1.0
unordered-containers 0.2.9.0
uri-bytestring 0.3.2.0
utf8-string 1.0.1.1
uuid-types 1.0.3
vault 0.3.1.1
vector 0.12.0.1
vector-algorithms 0.7.0.1
vector-instances 3.4
void 0.7.2
wai 3.2.1.2
wai-app-static 3.1.6.2
wai-extra 3.0.22.0
wai-logger 2.3.2
warp 3.2.22
word8 0.1.3
x509 1.7.3
x509-store 1.6.6
x509-system 1.6.6
x509-validation 1.6.10
xml-conduit 1.8.0
xml-types 0.3.6
xss-sanitize 0.3.5.7
yaml 0.8.30
yesod 1.6.0
yesod-auth 1.6.3
yesod-core 1.6.5
yesod-form 1.6.1
yesod-newsfeed 1.6.1.0
yesod-persistent 1.6.0
yesod-static 1.6.0
zlib 0.6.2

richard@linux-aovt:~> yesod version
yesod-bin version: 1.6.0.3
psibi commented 6 years ago

Just to be sure, can you try the following after issuing the command stack exec --yesod devel:

Let me know if that helps/doesn't help.

rszibele commented 6 years ago

Thanks for the quick response, psibi. Following your instructions, ExitSuccess no longer appears after a rebuild by pressing Enter in the console so I assume it should be running now. However, it still displays The application isn't built.

What I've also tried in the meanwhile:

I unfortunately still get the same issue.

rszibele commented 6 years ago

I tried and did exactly the same thing in a virtual machine on Ubuntu 18.04 and it works. I'll be investigating why it doesn't work on OpenSUSE Leap 15.

rszibele commented 6 years ago

Ok, this is strange. It only listens on ipv6 even though in the configuration (settings.yml) it should listen on any ipv4 address: _env:HOST:*4.

richard@linux-aovt:~> ss -ltn
State       Recv-Q Send-Q                                Local Address:Port                                               Peer Address:Port              
LISTEN      0      5                                         127.0.0.1:631                                                     0.0.0.0:*                  
LISTEN      0      100                                       127.0.0.1:25                                                      0.0.0.0:*                  
LISTEN      0      50                                                *:1716                                                          *:*                  
LISTEN      0      5                                             [::1]:631                                                        [::]:*                  
LISTEN      0      128          [2003:ec:ebde:500:307a:66cb:af80:d056]:3000                                                       [::]:*                  
LISTEN      0      100                                           [::1]:25                                                         [::]:*

Opening [2003:ec:ebde:500:307a:66cb:af80:d056]:3000 in Firefox shows the web page.

psibi commented 6 years ago

That's strange. I checked on my Ubuntu machine too and the template worked fine. Not really sure why this is happening with OpenSUSE.

rszibele commented 6 years ago

According to http://hackage.haskell.org/package/warp-3.2.22/docs/Network-Wai-Handler-Warp.html#t:HostPreference *4 means any IPv4 or IPv6 hostname, IPv4 preferred, so I thought changing it to !4 which means any IPv4 hostname would solve it, but I still get the same result. I also tried 127.0.0.1 or localhost without success.

rszibele commented 6 years ago

Found the issue, OpenSUSE doesn't bind the hostname to localhost on a fresh install which causes this issue.

rszibele commented 6 years ago

I'll have to reopen this as I've spoken with the lads over at freenode #SUSE and they say it's an issue with the framework as it shouldn't be a requirement that the hostname is bound to localhost. What I also find strange is that 127.0.0.1, localhost or !4 didn't work, it should, shouldn't it?

psibi commented 6 years ago

What I also find strange is that 127.0.0.1, localhost or !4 didn't work, it should, shouldn't it?

!4 should have worked. 127.0.0.1 should have worked. But it seems to have assigned IPv6 to you. So that explains why that didn't work. localhost - Now if it's not binded, it won't work.

psibi commented 6 years ago

BTW, Thanks for the great debugging!

rszibele commented 6 years ago

localhost is bound to 127.0.0.1, but my computers hostname opensuse isn't bound to anything in /etc/hosts, sorry for not being clear. On Ubuntu the computers hostname is bound to a local address, but not on OpenSUSE.

psibi commented 6 years ago

@rszibele So, I looked on to this but I wasn't able to find anything interesting on a Ubuntu based Linux machine. Can you run this program in your SUSE machine:

#!/usr/bin/env stack
{- stack
     --resolver lts-11.6
     --install-ghc
     runghc
     --package warp
     --package wai
     --package http-types
 -}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

import Network.HTTP.Types
import Network.Wai
import Network.Wai.Handler.Warp

app :: Application
app _req sendResponse =
  sendResponse $
  responseLBS status200 [("Content-Type", "text/plain")] "Hello Warp!"

main :: IO ()
main = runSettings (setHost "!4" defaultSettings) app

For executing it, you should do stack filename.hs and check if localhost:3000 works in your browser. And after that can you show the paste the output of the following command here:

$ netstat -lntp

There was one odd behavior which I found using !6 which made it work in both ipv4 and ipv6. But after reading some documentation, that seems to be the case of IPv4-mapped IPv6 addresses. It would be good to document that behavior as part of HostPreferences IMO.

snoyberg commented 6 years ago

One minor FYI: if you're using yesod devel, you'll want to use the --host parameter on the command line to control which host yesod devel itself binds to. The config file will affect the application running behind yesod devel.

rszibele commented 6 years ago

@psibi Here's the output of netstat after executing your snippet. It's bound correctly and it works.

richard@opensuse:~/Documents> netstat -lntp
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN      -                   
tcp        0      0 0.0.0.0:3000            0.0.0.0:*               LISTEN      30801/ghc           
tcp        0      0 127.0.0.1:25            0.0.0.0:*               LISTEN      -                   
tcp6       0      0 :::1716                 :::*                    LISTEN      3018/kdeconnectd    
tcp6       0      0 ::1:631                 :::*                    LISTEN      -                   
tcp6       0      0 ::1:25                  :::*                    LISTEN      -

I've been debugging further and I've been wondering why your snippet works (as in, binds to IPv4) but the getting started project doesn't. It turns out that you pass !4 directly to WAI, while the yesod project detects the presence of the HOST environment variable and uses that instead if it is defined. OpenSUSE sets this variable by default.

richard@opensuse:~> echo $HOST
opensuse

If I change _env:HOST:*4 to *4 in settings.yml, the generated project works correctly as it no longer uses the HOST environment variable.

@snoyberg Now knowing that host gets set to opensuse on my computer and the setting gets overridden by default, I've also tried running stack exec -- yesod devel --host opensuse, and it works when I visit http://opensuse:3000 but it prints a bogus message:

Devel application launched: http://localhost:3000

It should actually be http://opensuse:3000 on my computer. The offending line: https://github.com/yesodweb/yesod/blob/master/yesod/Yesod/Default/Config2.hs#L97

To summarize what we've found:

Two possible solutions which would independently make the getting started projects work out-of-the box:

  1. Prefix the environment variables yesod looks for within these generated projects with something unique like YESOD_ to prevent clashing of environment variables. For example: _env:YESOD_HOST:*4 and _env:YESOD_PORT:3000.
  2. Make yesod devel autodetect and use the same host as the app.
snoyberg commented 6 years ago

I'll be honest: I'm not too terribly thrilled about making changes to Yesod for this case. Having localhost not working is pretty extreme. I'd be more willing to have a link on the quickstart page saying "You're on OpenSUSE? Click here." That said, I'm OK with prefixing YESOD_ in the template I think. I'm not at all convinced that yesod devel should do the same thing though; perhaps using IP address instead of localhost in the display would be OK.

rszibele commented 6 years ago

localhost itself works, it's just that yesod binds to the hostname by default and not localhost, which isn't the same thing on OpenSUSE.

The prefix would also fix it, so either of the solutions is a good fix.

StevenXL commented 6 years ago

I've updated the QuickStart guide for openSUSE users in this PR, as this was the easiest change that both @snoyberg and @rszibele agreed would be acceptable.

IF that PR is merged, I think we can close this issue.

snoyberg commented 6 years ago

The new templates have been pushed, can you give it a shot again and confirm that the problem has been solved?

rszibele commented 6 years ago

@snoyberg Yes, the problem has been resolved.

develop7 commented 6 years ago

it's just that yesod binds to the hostname by default and not localhost

confirming that, the HOST environment variable of yesod process is actually a default hostname instead of localhost. Which leads to question: why do we prefer it to the localhost or 127.0.0.1, like others do?