summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess2015-01-23 01:18:47 -0400
committerJoey Hess2015-01-23 01:18:47 -0400
commitd156a1e9ba202761512ee06e497614d58c658697 (patch)
tree1da4874746249077a2fb3f4d567f84acfb83d6cb
parent87c39431a49fc9be88ed826c48a3d6e81d038f8a (diff)
Added more network interface configuration properties.
-rw-r--r--config-joey.hs1
-rw-r--r--debian/changelog1
-rw-r--r--src/Propellor/Property/Network.hs87
3 files changed, 76 insertions, 13 deletions
diff --git a/config-joey.hs b/config-joey.hs
index 81066983..e1587076 100644
--- a/config-joey.hs
+++ b/config-joey.hs
@@ -141,6 +141,7 @@ kite = standardSystemUnhardened "kite.kitenet.net" Testing "amd64"
, (SshEd25519, "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFZftKMnH/zH29BHMKbcBO4QsgTrstYFVhbrzrlRzBO3")
]
+ & Network.static "eth0" `requires` Network.cleanInterfacesFile
& Apt.installed ["linux-image-amd64"]
& Linode.chainPVGrub 5
& Apt.unattendedUpgrades
diff --git a/debian/changelog b/debian/changelog
index a5f22d12..18a8a366 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,7 @@ propellor (1.4.0) UNRELEASED; urgency=medium
* Fix info propigation from fallback combinator's second Property.
* Added systemd configuration properties.
* Added journald configuration properties.
+ * Added more network interface configuration properties.
-- Joey Hess <id@joeyh.name> Thu, 15 Jan 2015 20:14:29 -0400
diff --git a/src/Propellor/Property/Network.hs b/src/Propellor/Property/Network.hs
index c557d453..e04290aa 100644
--- a/src/Propellor/Property/Network.hs
+++ b/src/Propellor/Property/Network.hs
@@ -5,21 +5,73 @@ import Propellor.Property.File
type Interface = String
-interfaces :: FilePath
-interfaces = "/etc/network/interfaces"
+ifUp :: Interface -> Property
+ifUp iface = cmdProperty "ifup" [iface]
-interfaceFile :: Interface -> FilePath
-interfaceFile iface = "/etc/network/interfaces.d" </> iface
+-- | Resets /etc/network/interfaces to a clean and empty state,
+-- containing just the standard loopback interface, and with
+-- interfacesD enabled.
+--
+-- This can be used as a starting point to defining other interfaces.
+--
+-- No interfaces are brought up or down by this property.
+cleanInterfacesFile :: Property
+cleanInterfacesFile = hasContent interfacesFile
+ [ "# Deployed by propellor, do not edit."
+ , ""
+ , "source-directory interfaces.d"
+ , ""
+ , "# The loopback network interface"
+ , "auto lo"
+ , "iface lo inet loopback"
+ ]
+ `describe` ("clean " ++ interfacesFile)
--- | Enable source-directory interfaces.d
-interfacesD :: Property
-interfacesD = containsLine interfaces "source-directory interfaces.d"
- `describe` "interfaces.d directory enabled"
+-- | Writes a static interface file for the specified interface.
+--
+-- The interface has to be up already. It could have been brought up by
+-- DHCP, or by other means. The current ipv4 addresses
+-- and routing configuration of the interface are written into the file.
+--
+-- If the interface file already exists, this property does nothing,
+-- no matter its content.
+--
+-- (ipv6 addresses are not included because it's assumed they come up
+-- automatically in most situations.)
+static :: Interface -> Property
+static iface = check (not <$> doesFileExist f) setup
+ `describe` desc
+ `requires` interfacesDEnabled
+ where
+ f = interfaceDFile iface
+ desc = "static " ++ iface
+ setup = property desc $ do
+ ls <- liftIO $ lines <$> readProcess "ip"
+ ["-o", "addr", "show", iface, "scope", "global"]
+ stanzas <- liftIO $ concat <$> mapM mkstanza ls
+ ensureProperty $ hasContent f $ ("auto " ++ iface) : stanzas
+ mkstanza ipline = case words ipline of
+ -- Note that the IP address is written CIDR style, so
+ -- the netmask does not need to be specified separately.
+ (_:iface':"inet":addr:_) | iface' == iface -> do
+ gw <- getgateway
+ return $ catMaybes
+ [ Just $ "iface " ++ iface ++ " inet static"
+ , Just $ "\taddress " ++ addr
+ , ("\tgateway " ++) <$> gw
+ ]
+ _ -> return []
+ getgateway = do
+ rs <- lines <$> readProcess "ip"
+ ["route", "show", "scope", "global", "dev", iface]
+ return $ case words <$> headMaybe rs of
+ Just ("default":"via":gw:_) -> Just gw
+ _ -> Nothing
-- | 6to4 ipv6 connection, should work anywhere
ipv6to4 :: Property
-ipv6to4 = hasContent (interfaceFile "sit0")
- [ "# Automatically added by propeller"
+ipv6to4 = hasContent (interfaceDFile "sit0")
+ [ "# Deployed by propellor, do not edit."
, "iface sit0 inet6 static"
, "\taddress 2002:5044:5531::1"
, "\tnetmask 64"
@@ -27,8 +79,17 @@ ipv6to4 = hasContent (interfaceFile "sit0")
, "auto sit0"
]
`describe` "ipv6to4"
- `requires` interfacesD
+ `requires` interfacesDEnabled
`onChange` ifUp "sit0"
-ifUp :: Interface -> Property
-ifUp iface = cmdProperty "ifup" [iface]
+interfacesFile :: FilePath
+interfacesFile = "/etc/network/interfaces"
+
+-- | A file in the interfaces.d directory.
+interfaceDFile :: Interface -> FilePath
+interfaceDFile iface = "/etc/network/interfaces.d" </> iface
+
+-- | Ensures that files in the the interfaces.d directory are used.
+interfacesDEnabled :: Property
+interfacesDEnabled = containsLine interfacesFile "source-directory interfaces.d"
+ `describe` "interfaces.d directory enabled"