module Puppet.NativeTypes.Helpers where
import Puppet.Interpreter.Types
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.Char (isDigit)
import Control.Monad
type PuppetTypeName = String
type PuppetTypeValidate = RResource -> Either String RResource
data PuppetTypeMethods = PuppetTypeMethods {
puppetvalidate :: PuppetTypeValidate,
puppetfields :: Set.Set String
}
faketype :: PuppetTypeName -> (PuppetTypeName, PuppetTypeMethods)
faketype tname = (tname, PuppetTypeMethods Right Set.empty)
defaulttype :: PuppetTypeName -> (PuppetTypeName, PuppetTypeMethods)
defaulttype tname = (tname, PuppetTypeMethods (defaultValidate Set.empty) Set.empty)
defaultValidate :: Set.Set String -> PuppetTypeValidate
defaultValidate validparameters = checkParameterList validparameters >=> addDefaults
checkParameterList :: Set.Set String -> PuppetTypeValidate
checkParameterList validparameters res | Set.null validparameters = Right res
| otherwise = if Set.null setdiff
then Right res
else Left $ "Unknown parameters " ++ show (Set.toList setdiff)
where
keyset = Map.keysSet (rrparams res)
setdiff = Set.difference keyset (Set.union metaparameters validparameters)
addDefaults :: PuppetTypeValidate
addDefaults res = Right (res { rrparams = newparams } )
where
newparams = Map.filter (/= ResolvedUndefined) $ Map.union (rrparams res) defaults
defaults = Map.fromList [("name", nm),("title", nm)]
nm = ResolvedString $ rrname res
runarray :: String -> (String -> ResolvedValue -> PuppetTypeValidate) -> PuppetTypeValidate
runarray param func res = case Map.lookup param (rrparams res) of
Just (ResolvedArray x) -> foldM (\res' cu -> func param cu res') res x
Just x -> Left $ "Parameter " ++ param ++ " should be an array, not " ++ show x
Nothing -> Right res
string :: String -> PuppetTypeValidate
string param res = case Map.lookup param (rrparams res) of
Just x -> string' param x res
Nothing -> Right res
strings :: String -> PuppetTypeValidate
strings param = runarray param string'
string' :: String -> ResolvedValue -> PuppetTypeValidate
string' param re res = case re of
ResolvedString _ -> Right res
ResolvedInt n -> Right (insertparam res param (ResolvedString $ show n))
ResolvedBool True -> Right (insertparam res param (ResolvedString "true"))
ResolvedBool False -> Right (insertparam res param (ResolvedString "false"))
x -> Left $ "Parameter " ++ param ++ " should be a string, and not " ++ show x
values :: [String] -> String -> PuppetTypeValidate
values valuelist param res = case (Map.lookup param (rrparams res)) of
Just (ResolvedString x) -> if elem x valuelist
then Right res
else Left $ "Parameter " ++ param ++ " value should be one of " ++ show valuelist ++ " and not " ++ x
Just x -> Left $ "Parameter " ++ param ++ " value should be one of " ++ show valuelist ++ " and not " ++ show x
Nothing -> Right res
defaultvalue :: String -> String -> PuppetTypeValidate
defaultvalue value param res = case (Map.lookup param (rrparams res)) of
Just _ -> Right res
Nothing -> Right $ insertparam res param (ResolvedString value)
insertparam :: RResource -> String -> ResolvedValue -> RResource
insertparam res param value = res { rrparams = Map.insert param value (rrparams res) }
integer :: String -> PuppetTypeValidate
integer prm res = string prm res >>= integer' prm
where
integer' pr rs = case (Map.lookup pr (rrparams rs)) of
Just x -> integer'' prm x res
Nothing -> Right rs
integers :: String -> PuppetTypeValidate
integers param = runarray param integer''
integer'' :: String -> ResolvedValue -> PuppetTypeValidate
integer'' param val res = case val of
ResolvedString x -> if all isDigit x
then Right $ insertparam res param (ResolvedInt $ read x)
else Left $ "Parameter " ++ param ++ " should be a number"
ResolvedInt _ -> Right res
_ -> Left $ "Parameter " ++ param ++ " must be an integer"
nameval :: String -> PuppetTypeValidate
nameval prm res = do
nres <- string prm res
case Map.lookup "name" (rrparams res) of
Just (ResolvedString nm) -> defaultvalue nm prm nres
Just x -> Left $ "Parameter name should be a string, and not " ++ show x
Nothing -> Left "Parameter name not set."
mandatory :: String -> PuppetTypeValidate
mandatory param res = case Map.lookup param (rrparams res) of
Just _ -> Right res
Nothing -> Left $ "Parameter " ++ param ++ " should be set."
parameterFunctions :: [(String, [String -> PuppetTypeValidate])] -> PuppetTypeValidate
parameterFunctions argrules rs = foldM parameterFunctions' rs argrules
where
parameterFunctions' :: RResource -> (String, [String -> PuppetTypeValidate]) -> Either String RResource
parameterFunctions' r (param, validationfunctions) = foldM (parameterFunctions'' param) r validationfunctions
parameterFunctions'' :: String -> RResource -> (String -> PuppetTypeValidate) -> Either String RResource
parameterFunctions'' param r validationfunction = validationfunction param r
fullyQualified :: String -> PuppetTypeValidate
fullyQualified param res = case Map.lookup param (rrparams res) of
Just path -> fullyQualified' param path res
Nothing -> Right res
fullyQualifieds :: String -> PuppetTypeValidate
fullyQualifieds param = runarray param fullyQualified'
fullyQualified' :: String -> ResolvedValue -> PuppetTypeValidate
fullyQualified' param path res = case path of
ResolvedString ("") -> Left $ "Empty path for parameter " ++ param
ResolvedString ('/':_) -> Right res
ResolvedString p -> Left $ "Path must be absolute, not " ++ p ++ " for parameter " ++ param
x -> Left $ "SHOULD NOT HAPPEN: path is not a resolved string, but " ++ show x ++ " for parameter " ++ show x
rarray :: String -> PuppetTypeValidate
rarray param res = case Map.lookup param (rrparams res) of
Just (ResolvedArray _) -> Right res
Just x -> Right $ insertparam res param (ResolvedArray [x])
Nothing -> Right res
ipaddr :: String -> PuppetTypeValidate
ipaddr param res = case Map.lookup param (rrparams res) of
Nothing -> Right res
Just (ResolvedString ip) ->
if checkipv4 ip 0
then Right res
else Left $ "Invalid IP address for parameter " ++ param
Just x -> Left $ "Parameter " ++ param ++ " should be an IP address string, not " ++ show x
checkipv4 :: String -> Int -> Bool
checkipv4 _ 4 = False
checkipv4 "" _ = False
checkipv4 ip v =
let (cur, nxt) = break (=='.') ip
nextfunc = if null nxt
then v == 3
else checkipv4 (tail nxt) (v+1)
goodcur = not (null cur) && all isDigit cur && (let rcur = read cur :: Int in (rcur >= 0) && (rcur <= 255))
in goodcur && nextfunc
inrange :: Integer -> Integer -> String -> PuppetTypeValidate
inrange mi ma param res = case Map.lookup param (rrparams res) of
Nothing -> Right res
Just (ResolvedInt v) -> if (v>=mi) && (v<=ma)
then Right res
else Left $ "Parameter " ++ param ++ "'s value should be between " ++ show mi ++ " and " ++ show ma
Just x -> Left $ "Parameter " ++ param ++ " should be an integer, and not " ++ show x