Skip to content

Commit

Permalink
Add support for YAML configuration files (#6)
Browse files Browse the repository at this point in the history
* config file can be YAML

* config file can be YAML

* config file can be YAML

* chore: update tailscalemanager
  • Loading branch information
dhyanio authored Dec 5, 2024
1 parent c402ddc commit eddf6d6
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 11 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ normally support App Connectors.

## Example

Here is a sample config file, in JSON format:
Create a configuration file in either JSON or YAML format. Here’s an example:

`config.json`
```json
{
"routes": [
Expand All @@ -50,6 +51,19 @@ Here is a sample config file, in JSON format:
]
}
```
or `config.yaml`
```yaml
routes:
- "172.16.0.0/22"
- "192.168.0.0/24"
hostRoutes:
- "special-hostname1.example"
- "special-hostname2.example"
awsManagedPrefixLists:
- "pl-02761f4a40454a3c9"
extraArgs:
- "--webclient"
```
Run tailscale-manager:
Expand Down
11 changes: 5 additions & 6 deletions src/TailscaleManager.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ helpText = [r|Tailscale routes manager
Dynamically resolves a list of hostRoutes to IP addresses, then tells tailscale
to advertise them as /32 routes along with any normal CIDR routes.

Config file example:
Config file example (JSON):

{
"routes": [
Expand All @@ -50,7 +50,7 @@ Config file example:
],
"hostRoutes": [
"special-hostname1.example",
"special-hostname2.example",
"special-hostname2.example"
],
"awsManagedPrefixLists": [
"pl-02761f4a40454a3c9"
Expand All @@ -61,7 +61,7 @@ Config file example:
tsManagerOptions :: Parser TailscaleManagerOptions
tsManagerOptions =
TailscaleManagerOptions
<$> argument str (metavar "<configfile.json>")
<$> argument str (metavar "<configfile>")
<*> switch (long "dryrun"
<> help "Dryrun mode")
<*> strOption (long "tailscale"
Expand Down Expand Up @@ -143,7 +143,7 @@ runOnce options prevRoutes = do
logDelay
return prevRoutes

-- |Emit a log message describing the difference between old and new route sets.
-- | Emit a log message describing the difference between old and new route sets.
logDiff :: Set IPRange -> Set IPRange -> IO ()
logDiff prevRoutes newRoutes = do
logger <- myLogger
Expand All @@ -170,8 +170,7 @@ shrinkRatio :: Foldable t
-> Double -- ^ Shrink ratio
shrinkRatio old new = 1 - (1 / (fromIntegral (length old) / fromIntegral (length new)))

-- |Do all the hostname resolution and concat the results with static routes from
-- the config.
-- | Generate routes based on config, resolving hostnames and AWS-managed prefix lists.
generateRoutes :: TSConfig -> IO (Set IPRange)
generateRoutes config = do
hostRoutes <- resolveHostnamesToRoutes (tsHostRoutes config)
Expand Down
31 changes: 27 additions & 4 deletions src/TailscaleManager/Config.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
module TailscaleManager.Config where

import Data.Aeson
import Data.Aeson (eitherDecodeFileStrict)
import Data.Aeson.IP ()
import Data.ByteString.Lazy qualified as LB
import Data.IP (IPRange)
import Data.Maybe (fromMaybe)
import Data.Text

-- |Parse our config file. May throw AesonException on failure.
loadConfig :: FilePath -> IO TSConfig
loadConfig fp = LB.readFile fp >>= throwDecode
import System.FilePath (takeExtension)
import Data.Yaml (decodeFileEither)

-- |Config file schema
data TSConfig
Expand All @@ -35,3 +34,27 @@ instance FromJSON TSConfig where
, tsExtraArgs = fromMaybe [] extraArgs
, tsAWSManagedPrefixLists = fromMaybe [] awsManagedPrefixLists
})

-- | Load configuration from a file, detecting format based on file extension.
loadConfig :: FilePath -> IO TSConfig
loadConfig path = do
case takeExtension path of
".json" -> loadConfigFromJSON path
".yaml" -> loadConfigFromYAML path
_ -> error "Unsupported file format. Please use .json or .yaml."

-- | Load configuration from a JSON file.
loadConfigFromJSON :: FilePath -> IO TSConfig
loadConfigFromJSON path = do
result <- eitherDecodeFileStrict path
case result of
Left err -> error $ "Failed to parse JSON config: " ++ err
Right config -> return config

-- | Load configuration from a YAML file.
loadConfigFromYAML :: FilePath -> IO TSConfig
loadConfigFromYAML path = do
result <- decodeFileEither path
case result of
Left err -> error $ "Failed to parse YAML config: " ++ show err
Right config -> return config
2 changes: 2 additions & 0 deletions tailscale-manager.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ common deps
, protolude ^>= 0.3.4
, raw-strings-qq ^>= 1.1
, text ^>= 2.0.2
, filepath ^>= 1.4.2
, yaml ^>= 0.11.8

executable tailscale-manager
import: warnings, deps
Expand Down

0 comments on commit eddf6d6

Please sign in to comment.