summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog10
-rw-r--r--doc/forum/Conceptual_:_HostName_vs._Domain.mdwn22
-rw-r--r--doc/forum/Conceptual_:_HostName_vs._Domain/comment_1_6a80853161714e19cdae006ec19097fb._comment21
-rw-r--r--doc/forum/Setting_altenative___63__.mdwn7
-rw-r--r--doc/forum/Setting_altenative___63__/comment_1_cc9f01e46e6cc2940382309cd17b3575._comment7
-rw-r--r--doc/forum/installing_apt_packages_without_running_new_services/comment_2_b819efe3a4f00f1b9993d5a31e65f2e9._comment99
-rw-r--r--doc/todo/Debootstrap_module_should_respect_a_configured_Apt.proxy.mdwn2
-rw-r--r--src/Propellor/Property/Chroot.hs52
-rw-r--r--src/Propellor/Property/Debootstrap.hs22
-rw-r--r--src/Propellor/Property/Sbuild.hs17
-rw-r--r--src/Propellor/Types/Core.hs3
-rw-r--r--src/Propellor/Types/Info.hs1
12 files changed, 241 insertions, 22 deletions
diff --git a/debian/changelog b/debian/changelog
index 3031d05a..4b79f8ab 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,19 @@
propellor (5.10.1) UNRELEASED; urgency=medium
+ [ Joey Hess ]
* Localdir.hasOriginUrl: Depend on Git.installed.
* Localdir.hasOriginUrl: Type changed from UnixLike to DebianLike
because Git.installed is not implemented for other unixes.
(API change)
+ * Changed the ChrootBootstrapper type class's buildchroot method
+ to take a Info parameter, instead of Maybe System.
+ (The System can be extracted from the Info.)
+ (API change)
+
+ [ Sean Whitton ]
+ * Chroot.{de,}bootstrapped uses the chroot's configured apt proxy and
+ mirror, if these exist, when debootstrapping the chroot.
+ * Rename Sbuild.useHostProxy -> Chroot.useHostProxy. (API change)
-- Joey Hess <id@joeyh.name> Thu, 08 Aug 2019 11:33:37 -0400
diff --git a/doc/forum/Conceptual_:_HostName_vs._Domain.mdwn b/doc/forum/Conceptual_:_HostName_vs._Domain.mdwn
new file mode 100644
index 00000000..334c9d82
--- /dev/null
+++ b/doc/forum/Conceptual_:_HostName_vs._Domain.mdwn
@@ -0,0 +1,22 @@
+Hello,
+
+Writing properties, I often hesitate between using types `HostName` or `Domain` for the FQDN of a machine.
+This is not 'very important' since both are "just" `String`, but the type carries semantics and I'd rather keep consistent (helps understanding the code better).
+
+Here are the docs :
+
+http://hackage.haskell.org/package/propellor-5.9.1/docs/Propellor-Types-OS.html#t:HostName
+http://hackage.haskell.org/package/propellor-5.9.1/docs/Propellor-Types-Dns.html#t:Domain
+
+So `HostName` documentation to me looks like really corresponding to a machine's FQDN, but may also be the IP of the machine.
+Conversely `Domain` is not documented (in its module) but it is used in the 'domain part of the FQDN' in some modules; eg. in Propellor/Property/Hostname.hs
+Even clearer is the `Propellor.Property.DNS` module in which I clearly understand the choice of `Domain` vs. `HostName`.
+
+Still it seems to me that sometimes one sees `Domain` where a `HostName` would be expected. One such example is in `LetsEncrypt`
+Maybe I am just to confused by a few places where `Domain` is used while I would (maybe wrongly) expect `HostName` ?
+
+What am I missing ?
+
+Cheers,
+
+Serge.
diff --git a/doc/forum/Conceptual_:_HostName_vs._Domain/comment_1_6a80853161714e19cdae006ec19097fb._comment b/doc/forum/Conceptual_:_HostName_vs._Domain/comment_1_6a80853161714e19cdae006ec19097fb._comment
new file mode 100644
index 00000000..86c38d79
--- /dev/null
+++ b/doc/forum/Conceptual_:_HostName_vs._Domain/comment_1_6a80853161714e19cdae006ec19097fb._comment
@@ -0,0 +1,21 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-11-11T17:26:24Z"
+ content="""
+I think LetsEncrypt's use of Domain is intentional; a certificate is for a
+domain and you can't get one for eg a bare IP address or an unqualified
+hostname.
+
+AFAICS, Domain is a FQDN.
+
+(Propellor.Property.Hostname has to deal with details of /etc/hosts,
+but it does not actually use the Domain type anywhere.)
+
+More generally, it's common for a propellor module to have some
+`type Foo = String` that's only used to make parameters more self-documenting
+and doesn't have any particular meaning beyond whatever string a Property might
+use. One shouldn't worry if two modules have data types that seem to
+overlap in content when that's all they're used for. Of course it's nicer to
+have less stringy data types, via ADTs or smart constructors, when possible.
+"""]]
diff --git a/doc/forum/Setting_altenative___63__.mdwn b/doc/forum/Setting_altenative___63__.mdwn
new file mode 100644
index 00000000..b40d1fe0
--- /dev/null
+++ b/doc/forum/Setting_altenative___63__.mdwn
@@ -0,0 +1,7 @@
+Everything is in the title : is there a property to ensure that the 'alternative' is set in a given way ?
+
+I guess the simplest otherwise would be to use a `Cmd` to do it (through usage of `update-alternative`), but I am wondering if there is already a property to do that…
+
+Thanks in advance,
+
+Serge
diff --git a/doc/forum/Setting_altenative___63__/comment_1_cc9f01e46e6cc2940382309cd17b3575._comment b/doc/forum/Setting_altenative___63__/comment_1_cc9f01e46e6cc2940382309cd17b3575._comment
new file mode 100644
index 00000000..741326f6
--- /dev/null
+++ b/doc/forum/Setting_altenative___63__/comment_1_cc9f01e46e6cc2940382309cd17b3575._comment
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 1"""
+ date="2019-11-11T17:23:24Z"
+ content="""
+There is not. I'd welcome a property submission.
+"""]]
diff --git a/doc/forum/installing_apt_packages_without_running_new_services/comment_2_b819efe3a4f00f1b9993d5a31e65f2e9._comment b/doc/forum/installing_apt_packages_without_running_new_services/comment_2_b819efe3a4f00f1b9993d5a31e65f2e9._comment
new file mode 100644
index 00000000..467e55cf
--- /dev/null
+++ b/doc/forum/installing_apt_packages_without_running_new_services/comment_2_b819efe3a4f00f1b9993d5a31e65f2e9._comment
@@ -0,0 +1,99 @@
+[[!comment format=mdwn
+ username="serge1cohen"
+ avatar="http://cdn.libravatar.org/avatar/df873622c2eeb5b34222b7af0d47abd0"
+ subject="Using noServices to configure apache before running it..."
+ date="2019-10-31T22:56:56Z"
+ content="""
+Hello there,
+
+I was typically in this situation : starting an apache server on a specific IP (the other IPs of the machine -on port 80- are used by other server processes), in particular to be able to get a certificate from let's encrypt.
+
+When using :
+
+ micro_apache :: Domain -> String -> FilePath -> Property DebianLike
+ micro_apache fqdn ip dr = combineProperties \"Setting a micro apache server running only for interface\" $ props
+ & Apache.installed
+ & File.hasContent \"/etc/apache2/ports.conf\" [(\"Listen \" ++ ip ++ \":80\")]
+ & Apache.siteDisabled \"000-default\"
+ & Apache.siteEnabled fqdn
+ [ \"<VirtualHost \" ++ ip ++ \":80>\"
+ , \"ServerName \" ++ fqdn ++ \":80\"
+ , \"DocumentRoot \" ++ dr
+ , \"ErrorLog /var/log/apache2/\" ++ fqdn ++ \"_error.log\"
+ , \"LogLevel warn\"
+ , \"CustomLog /var/log/apache2/\" ++ fqdn ++ \"_access.log combined\"
+ , \"ServerSignature On\"
+ , \"</VirtualHost>\"
+ ]
+ & Apache.restarted
+ & Apache.reloaded
+
+The property is problematic (the initial 'Apache.installed' starts the apache server listening to ALL IPs).
+But at least at the end it seems that I get a 'running' service :
+
+ root@d4:~# systemctl status apache2.service
+ ● apache2.service - The Apache HTTP Server
+ Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
+ Active: active (running) since Thu 2019-10-31 16:59:41 CET; 17min ago
+
+
+
+To avoid the transient service wrongly configured (it also messes up with the server serving port 80 on another IP) case I tried :
+
+ micro_apache :: Domain -> String -> FilePath -> Property (HasInfo + DebianLike)
+ micro_apache fqdn ip dr = combineProperties \"Setting a micro apache server running only for interface\" $ props
+ & ( Apache.installed `requires` Service.noServices ) -- => Needs to change type to Property (HasInfo + DebianLike)
+ & File.hasContent \"/etc/apache2/ports.conf\" [(\"Listen \" ++ ip ++ \":80\")]
+ & Apache.siteDisabled \"000-default\"
+ & Apache.siteEnabled fqdn
+ [ \"<VirtualHost \" ++ ip ++ \":80>\"
+ , \"ServerName \" ++ fqdn ++ \":80\"
+ , \"DocumentRoot \" ++ dr
+ , \"ErrorLog /var/log/apache2/\" ++ fqdn ++ \"_error.log\"
+ , \"LogLevel warn\"
+ , \"CustomLog /var/log/apache2/\" ++ fqdn ++ \"_access.log combined\"
+ , \"ServerSignature On\"
+ , \"</VirtualHost>\"
+ ]
+ & ( revert Service.noServices `before` Apache.restarted ) -- => Needs to change type to Property (HasInfo + DebianLike)
+
+But then the configuration leads to having apache in an \"ghost state\", neither started nor stopped :
+
+ root@d4:~# systemctl status apache2
+ ● apache2.service - The Apache HTTP Server
+ Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
+ Active: inactive (dead)
+ Docs: https://httpd.apache.org/docs/2.4/
+
+Which leads to an unavailable http service, and as a consequence to a failure in ACME / let's encrypt.
+Indeed it seems that the service is started using the 'old' Service system. The nice thing is that this makes it possible to use the 'noServices' property. The problem is that the systemd module is in a state not working anymore with 'Service'.
+
+Finally I had to mix the 'noServices' property with a couple of 'Systemd' properties so that the server is properly restarted once the configuration is correct. This leads to a bit longer property but at least it works :
+
+ micro_apache :: Domain -> String -> FilePath -> Property (HasInfo + DebianLike)
+ micro_apache fqdn ip dr = combineProperties \"Setting a micro apache server running only for interface\" $ props
+ & ( Apache.installed `requires` Service.noServices ) -- => Needs to change type to Property (HasInfo + DebianLike)
+ & Systemd.stopped \"apache2\" -- 'clean' of the systemd module
+ & File.hasContent \"/etc/apache2/ports.conf\" [(\"Listen \" ++ ip ++ \":80\")]
+ & Apache.siteDisabled \"000-default\"
+ & Apache.siteEnabled fqdn
+ [ \"<VirtualHost \" ++ ip ++ \":80>\"
+ , \"ServerName \" ++ fqdn ++ \":80\"
+ , \"DocumentRoot \" ++ dr
+ , \"ErrorLog /var/log/apache2/\" ++ fqdn ++ \"_error.log\"
+ , \"LogLevel warn\"
+ , \"CustomLog /var/log/apache2/\" ++ fqdn ++ \"_access.log combined\"
+ , \"ServerSignature On\"
+ , \"</VirtualHost>\"
+ ]
+ & ( revert Service.noServices -- => Needs to change type to Property (HasInfo + DebianLike)
+ `before` Systemd.running \"apache2\" ) -- restarting through systemd
+
+With this done, it seems to work.
+
+Notice, however, that if apache was completely avoiding the 'old service' system, then we could not even benefit from the 'noService' in the first place. Would there be another solution to reach the same result ?
+
+Hope this might help
+
+Serge.
+"""]]
diff --git a/doc/todo/Debootstrap_module_should_respect_a_configured_Apt.proxy.mdwn b/doc/todo/Debootstrap_module_should_respect_a_configured_Apt.proxy.mdwn
index 8887f438..fc817415 100644
--- a/doc/todo/Debootstrap_module_should_respect_a_configured_Apt.proxy.mdwn
+++ b/doc/todo/Debootstrap_module_should_respect_a_configured_Apt.proxy.mdwn
@@ -27,3 +27,5 @@ so tried on my own
to my opinion the schroot config file generated by Sbuild property does something wrong.
Cheers
+
+> [[done]]; I merged patches from spwhitton. --[[Joey]]
diff --git a/src/Propellor/Property/Chroot.hs b/src/Propellor/Property/Chroot.hs
index 48d96dcf..13511902 100644
--- a/src/Propellor/Property/Chroot.hs
+++ b/src/Propellor/Property/Chroot.hs
@@ -10,6 +10,7 @@ module Propellor.Property.Chroot (
Debootstrapped(..),
ChrootTarball(..),
exposeTrueLocaldir,
+ useHostProxy,
-- * Internal use
provisioned',
propagateChrootInfo,
@@ -26,6 +27,7 @@ import Propellor.Types.Container
import Propellor.Types.Info
import Propellor.Types.Core
import Propellor.Property.Chroot.Util
+import qualified Propellor.Property.Apt as Apt
import qualified Propellor.Property.Debootstrap as Debootstrap
import qualified Propellor.Property.Systemd.Core as Systemd
import qualified Propellor.Property.File as File
@@ -60,7 +62,11 @@ class ChrootBootstrapper b where
-- | Do initial bootstrapping of an operating system in a chroot.
-- If the operating System is not supported, return
-- Left error message.
- buildchroot :: b -> Maybe System -> FilePath -> Either String (Property Linux)
+ buildchroot
+ :: b
+ -> Info -- ^ info of the Properties of the chroot
+ -> FilePath -- ^ where to bootstrap the chroot
+ -> Either String (Property Linux)
-- | Use this to bootstrap a chroot by extracting a tarball.
--
@@ -91,14 +97,28 @@ extractTarball target src = check (isUnpopulated target) $
data Debootstrapped = Debootstrapped Debootstrap.DebootstrapConfig
instance ChrootBootstrapper Debootstrapped where
- buildchroot (Debootstrapped cf) system loc = case system of
+ buildchroot (Debootstrapped cf) info loc = case system of
(Just s@(System (Debian _ _) _)) -> Right $ debootstrap s
(Just s@(System (Buntish _) _)) -> Right $ debootstrap s
(Just (System ArchLinux _)) -> Left "Arch Linux not supported by debootstrap."
(Just (System (FreeBSD _) _)) -> Left "FreeBSD not supported by debootstrap."
Nothing -> Left "Cannot debootstrap; OS not specified"
where
- debootstrap s = Debootstrap.built loc s cf
+ debootstrap s = Debootstrap.built loc s
+ (cf <> proxyConf <> mirrorConf)
+ system = fromInfoVal (fromInfo info)
+ -- If the chroot has a configured apt proxy and/or mirror, pass
+ -- these on to debootstrap. Note that Debootstrap.built does
+ -- not get passed the Chroot, so the info inspection has to
+ -- happen here, not there
+ proxyConf = case (fromInfoVal . fromInfo) info of
+ Just (Apt.HostAptProxy u) ->
+ Debootstrap.DebootstrapProxy u
+ Nothing -> mempty
+ mirrorConf = case (fromInfoVal . fromInfo) info of
+ Just (Apt.HostMirror u) ->
+ Debootstrap.DebootstrapMirror u
+ Nothing -> mempty
-- | Defines a Chroot at the given location, built with debootstrap.
--
@@ -106,6 +126,11 @@ instance ChrootBootstrapper Debootstrapped where
-- add a property such as `osDebian` to specify the operating system
-- to bootstrap.
--
+-- If the 'Debootstrap.DebootstrapConfig' does not include a
+-- 'Debootstrap.DebootstrapMirror',
+-- any 'Apt.mirror' property of the chroot will configure debootstrap.
+-- Same for 'Debootstrap.DebootstrapProxy' and 'Apt.proxy'.
+--
-- > debootstrapped Debootstrap.BuildD "/srv/chroot/ghc-dev" $ props
-- > & osDebian Unstable X86_64
-- > & Apt.installed ["ghc", "haskell-platform"]
@@ -115,6 +140,10 @@ debootstrapped conf = bootstrapped (Debootstrapped conf)
-- | Defines a Chroot at the given location, bootstrapped with the
-- specified ChrootBootstrapper.
+--
+-- Like 'Chroot.debootstrapped', if the 'ChrootBootstrapper' is
+-- 'Debootstrapped', this property respects the Chroot's
+-- 'Apt.proxy' and 'Apt.mirror' properties.
bootstrapped :: ChrootBootstrapper b => b -> FilePath -> Props metatypes -> Chroot
bootstrapped bootstrapper location ps = c
where
@@ -143,7 +172,7 @@ provisioned' c@(Chroot loc bootstrapper infopropigator _) systemdonly caps =
setup = propellChroot c (inChrootProcess (not systemdonly) c) systemdonly caps
`requires` built
- built = case buildchroot bootstrapper (chrootSystem c) loc of
+ built = case buildchroot bootstrapper (containerInfo c) loc of
Right p -> p
Left e -> cantbuild e
@@ -304,3 +333,18 @@ propagateHostChrootInfo :: Host -> InfoPropagator
propagateHostChrootInfo h c pinfo p =
propagateContainer (hostName h) c pinfo $
p `setInfoProperty` chrootInfo c
+
+-- | Ensure that a chroot uses the host's Apt proxy.
+--
+-- This property is often used for 'Sbuild.built' chroots, when the host has
+-- 'Apt.useLocalCacher'.
+useHostProxy :: Host -> Property DebianLike
+useHostProxy h = property' "use host's apt proxy" $ \w ->
+ -- Note that we can't look at getProxyInfo outside the property,
+ -- as that would loop, but it's ok to look at it inside the
+ -- property. Thus the slightly strange construction here.
+ case getProxyInfo h of
+ Just (Apt.HostAptProxy u) -> ensureProperty w (Apt.proxy' u)
+ Nothing -> noChange
+ where
+ getProxyInfo = fromInfoVal . fromInfo . hostInfo
diff --git a/src/Propellor/Property/Debootstrap.hs b/src/Propellor/Property/Debootstrap.hs
index 6336e775..adf0879b 100644
--- a/src/Propellor/Property/Debootstrap.hs
+++ b/src/Propellor/Property/Debootstrap.hs
@@ -32,6 +32,8 @@ data DebootstrapConfig
| BuilddD
| DebootstrapParam String
| UseEmulation
+ | DebootstrapProxy Url
+ | DebootstrapMirror Url
| DebootstrapConfig :+ DebootstrapConfig
deriving (Show)
@@ -48,6 +50,8 @@ toParams MinBase = [Param "--variant=minbase"]
toParams BuilddD = [Param "--variant=buildd"]
toParams (DebootstrapParam p) = [Param p]
toParams UseEmulation = []
+toParams (DebootstrapProxy _) = []
+toParams (DebootstrapMirror _) = []
toParams (c1 :+ c2) = toParams c1 <> toParams c2
useEmulation :: DebootstrapConfig -> Bool
@@ -55,6 +59,16 @@ useEmulation UseEmulation = True
useEmulation (a :+ b) = useEmulation a || useEmulation b
useEmulation _ = False
+debootstrapProxy :: DebootstrapConfig -> Maybe Url
+debootstrapProxy (DebootstrapProxy u) = Just u
+debootstrapProxy (a :+ b) = debootstrapProxy a <|> debootstrapProxy b
+debootstrapProxy _ = Nothing
+
+debootstrapMirror :: DebootstrapConfig -> Maybe Url
+debootstrapMirror (DebootstrapMirror u) = Just u
+debootstrapMirror (a :+ b) = debootstrapMirror a <|> debootstrapMirror b
+debootstrapMirror _ = Nothing
+
-- | Builds a chroot in the given directory using debootstrap.
--
-- The System can be any OS and architecture that debootstrap
@@ -99,11 +113,15 @@ built' installprop target system@(System _ arch) config =
[ Param $ "--arch=" ++ architectureToDebianArchString arch
, Param suite
, Param target
- ]
+ ] ++ case debootstrapMirror config of
+ Just u -> [Param u]
+ Nothing -> []
cmd <- if useEmulation config
then pure "qemu-debootstrap"
else fromMaybe "debootstrap" <$> programPath
- de <- standardPathEnv
+ de <- case debootstrapProxy config of
+ Just u -> addEntry "http_proxy" u <$> standardPathEnv
+ Nothing -> standardPathEnv
ifM (boolSystemEnv cmd params (Just de))
( return MadeChange
, return FailedChange
diff --git a/src/Propellor/Property/Sbuild.hs b/src/Propellor/Property/Sbuild.hs
index 1562f80e..3242014d 100644
--- a/src/Propellor/Property/Sbuild.hs
+++ b/src/Propellor/Property/Sbuild.hs
@@ -31,7 +31,7 @@ Suggested usage in @config.hs@:
> & osDebian Unstable X86_32
> & Sbuild.osDebianStandard
> & Sbuild.update `period` Weekly (Just 1)
-> & Sbuild.useHostProxy mybox
+> & Chroot.useHostProxy mybox
If you are using sbuild older than 0.70.0, you also need:
@@ -65,7 +65,6 @@ module Propellor.Property.Sbuild (
built,
-- * Properties for use inside sbuild schroots
update,
- useHostProxy,
osDebianStandard,
-- * Global sbuild configuration
-- blockNetwork,
@@ -268,20 +267,6 @@ osDebianStandard = propertyList "standard Debian sbuild properties" $ props
update :: Property DebianLike
update = Apt.update `before` Apt.upgrade `before` Apt.autoRemove
--- | Ensure that an sbuild schroot uses the host's Apt proxy.
---
--- This property is typically used when the host has 'Apt.useLocalCacher'.
-useHostProxy :: Host -> Property DebianLike
-useHostProxy h = property' "use host's apt proxy" $ \w ->
- -- Note that we can't look at getProxyInfo outside the property,
- -- as that would loop, but it's ok to look at it inside the
- -- property. Thus the slightly strange construction here.
- case getProxyInfo of
- Just (Apt.HostAptProxy u) -> ensureProperty w (Apt.proxy' u)
- Nothing -> noChange
- where
- getProxyInfo = fromInfoVal . fromInfo . hostInfo $ h
-
aptCacheLine :: String
aptCacheLine = "/var/cache/apt/archives /var/cache/apt/archives none rw,bind 0 0"
diff --git a/src/Propellor/Types/Core.hs b/src/Propellor/Types/Core.hs
index 88c749b3..9f4dc519 100644
--- a/src/Propellor/Types/Core.hs
+++ b/src/Propellor/Types/Core.hs
@@ -109,3 +109,6 @@ instance IsProp ChildProperty where
getInfo (ChildProperty _ _ i _) = i
toChildProperty = id
getSatisfy (ChildProperty _ a _ _) = a
+
+propsInfo :: Props metatypes -> Info
+propsInfo (Props l) = mconcat (map getInfo l)
diff --git a/src/Propellor/Types/Info.hs b/src/Propellor/Types/Info.hs
index b941cc8f..27633712 100644
--- a/src/Propellor/Types/Info.hs
+++ b/src/Propellor/Types/Info.hs
@@ -63,6 +63,7 @@ addInfo (Info l) v = Info (l++[InfoEntry v])
toInfo :: IsInfo v => v -> Info
toInfo = addInfo mempty
+-- | Extracts a value from an Info.
fromInfo :: IsInfo v => Info -> v
fromInfo (Info l) = mconcat (mapMaybe extractInfoEntry l)