language-puppet 1.4.4 → 1.4.5
raw patch · 29 files changed
+568/−177 lines, 29 filesdep ~aesondep ~bytestringdep ~formattingPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: aeson, bytestring, formatting, hspec, lens, memory, mtl, protolude, scientific, servant, servant-client, text, vector
API changes (from Hackage documentation)
+ Hiera.Server: mergeWith :: MonadError PrettyError m => HieraQueryType -> PValue -> PValue -> m PValue
+ Hiera.Server: varSplitter :: Text -> [Text]
+ XPrelude: logErrorStr :: String -> IO ()
- Facter: class HasFactInfo c_a1T6j
+ Facter: class HasFactInfo c_a1T7y
- Facter: factInfo :: HasFactInfo c_a1T6j => Lens' c_a1T6j FactInfo
+ Facter: factInfo :: HasFactInfo c_a1T7y => Lens' c_a1T7y FactInfo
- Facter: factInfoName :: HasFactInfo c_a1T6j => Lens' c_a1T6j Text
+ Facter: factInfoName :: HasFactInfo c_a1T7y => Lens' c_a1T7y Text
- Facter: factInfoNodename :: HasFactInfo c_a1T6j => Lens' c_a1T6j NodeName
+ Facter: factInfoNodename :: HasFactInfo c_a1T7y => Lens' c_a1T7y NodeName
- Facter: factInfoVal :: HasFactInfo c_a1T6j => Lens' c_a1T6j PValue
+ Facter: factInfoVal :: HasFactInfo c_a1T7y => Lens' c_a1T7y PValue
- Hiera.Server: type HieraQueryFunc m = Container Text " Scope: all variables that Hiera can interpolate (the top level ones are prefixed with '::')" -> Text " The query" -> HieraQueryType -> m (Either PrettyError (Maybe PValue))
+ Hiera.Server: type HieraQueryFunc m = Container PValue " Scope: all variables that Hiera can interpolate (the top level ones are prefixed with '::')" -> Text " The query" -> HieraQueryType -> ExceptT PrettyError m (Maybe PValue)
- Puppet.Interpreter: [HieraQuery] :: Container Text -> Text -> HieraQueryType -> InterpreterInstr (Maybe PValue)
+ Puppet.Interpreter: [HieraQuery] :: Container PValue -> Text -> HieraQueryType -> InterpreterInstr (Maybe PValue)
- Puppet.Interpreter: environmentLayer :: forall m_a2vPL. Lens' (HieraQueryLayers m_a2vPL) (HieraQueryFunc m_a2vPL)
+ Puppet.Interpreter: environmentLayer :: forall m_a2xgk. Lens' (HieraQueryLayers m_a2xgk) (HieraQueryFunc m_a2xgk)
- Puppet.Interpreter: globalLayer :: forall m_a2vPL. Lens' (HieraQueryLayers m_a2vPL) (HieraQueryFunc m_a2vPL)
+ Puppet.Interpreter: globalLayer :: forall m_a2xgk. Lens' (HieraQueryLayers m_a2xgk) (HieraQueryFunc m_a2xgk)
- Puppet.Interpreter: ioGetCurrentCallStack :: forall m_a2vPM. Lens' (IoMethods m_a2vPM) (m_a2vPM [String])
+ Puppet.Interpreter: ioGetCurrentCallStack :: forall m_a2xgl. Lens' (IoMethods m_a2xgl) (m_a2xgl [String])
- Puppet.Interpreter: ioReadFile :: forall m_a2vPM. Lens' (IoMethods m_a2vPM) ([Text] -> m_a2vPM (Either String Text))
+ Puppet.Interpreter: ioReadFile :: forall m_a2xgl. Lens' (IoMethods m_a2xgl) ([Text] -> m_a2xgl (Either String Text))
- Puppet.Interpreter: ioTraceEvent :: forall m_a2vPM. Lens' (IoMethods m_a2vPM) (String -> m_a2vPM ())
+ Puppet.Interpreter: ioTraceEvent :: forall m_a2xgl. Lens' (IoMethods m_a2xgl) (String -> m_a2xgl ())
- Puppet.Interpreter: moduleLayer :: forall m_a2vPL. Lens' (HieraQueryLayers m_a2vPL) (Container (HieraQueryFunc m_a2vPL))
+ Puppet.Interpreter: moduleLayer :: forall m_a2xgk. Lens' (HieraQueryLayers m_a2xgk) (Container (HieraQueryFunc m_a2xgk))
- Puppet.Interpreter: readerExternalFunc :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (Container ([PValue] -> InterpreterMonad PValue))
+ Puppet.Interpreter: readerExternalFunc :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (Container ([PValue] -> InterpreterMonad PValue))
- Puppet.Interpreter: readerExternalModules :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (HashSet Text)
+ Puppet.Interpreter: readerExternalModules :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (HashSet Text)
- Puppet.Interpreter: readerFacts :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (Container PValue)
+ Puppet.Interpreter: readerFacts :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (Container PValue)
- Puppet.Interpreter: readerGetStatement :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (TopLevelType -> Text -> m_a2vPK (Either PrettyError Statement))
+ Puppet.Interpreter: readerGetStatement :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (TopLevelType -> Text -> m_a2xgj (Either PrettyError Statement))
- Puppet.Interpreter: readerGetTemplate :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (TemplateSource -> InterpreterState -> InterpreterReader m_a2vPK -> m_a2vPK (Either PrettyError Text))
+ Puppet.Interpreter: readerGetTemplate :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (TemplateSource -> InterpreterState -> InterpreterReader m_a2xgj -> m_a2xgj (Either PrettyError Text))
- Puppet.Interpreter: readerHieraQuery :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (HieraQueryLayers m_a2vPK)
+ Puppet.Interpreter: readerHieraQuery :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (HieraQueryLayers m_a2xgj)
- Puppet.Interpreter: readerIgnoredModules :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (HashSet Text)
+ Puppet.Interpreter: readerIgnoredModules :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (HashSet Text)
- Puppet.Interpreter: readerIoMethods :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (IoMethods m_a2vPK)
+ Puppet.Interpreter: readerIoMethods :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (IoMethods m_a2xgj)
- Puppet.Interpreter: readerIsStrict :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) Bool
+ Puppet.Interpreter: readerIsStrict :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) Bool
- Puppet.Interpreter: readerNativeTypes :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (Container NativeTypeMethods)
+ Puppet.Interpreter: readerNativeTypes :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (Container NativeTypeMethods)
- Puppet.Interpreter: readerNodename :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) Text
+ Puppet.Interpreter: readerNodename :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) Text
- Puppet.Interpreter: readerPdbApi :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (PuppetDBAPI m_a2vPK)
+ Puppet.Interpreter: readerPdbApi :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (PuppetDBAPI m_a2xgj)
- Puppet.Interpreter: readerPuppetPaths :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) PuppetDirPaths
+ Puppet.Interpreter: readerPuppetPaths :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) PuppetDirPaths
- Puppet.Interpreter: readerRebaseFile :: forall m_a2vPK. Lens' (InterpreterReader m_a2vPK) (Maybe FilePath)
+ Puppet.Interpreter: readerRebaseFile :: forall m_a2xgj. Lens' (InterpreterReader m_a2xgj) (Maybe FilePath)
- Puppet.Language: baseDir :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Language: baseDir :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Language: class HasLinkInformation c_aOd9
+ Puppet.Language: class HasLinkInformation c_aOeo
- Puppet.Language: class HasNativeTypeMethods c_aYsx
+ Puppet.Language: class HasNativeTypeMethods c_aYtM
- Puppet.Language: class HasPuppetDirPaths c_avEe
+ Puppet.Language: class HasPuppetDirPaths c_avFt
- Puppet.Language: class HasRIdentifier c_aNxZ
+ Puppet.Language: class HasRIdentifier c_aNze
- Puppet.Language: class HasResource c_aNnl
+ Puppet.Language: class HasResource c_aNoA
- Puppet.Language: class HasWireCatalog c_aWBF
+ Puppet.Language: class HasWireCatalog c_aWCU
- Puppet.Language: iname :: HasRIdentifier c_aNxZ => Lens' c_aNxZ Text
+ Puppet.Language: iname :: HasRIdentifier c_aNze => Lens' c_aNze Text
- Puppet.Language: itype :: HasRIdentifier c_aNxZ => Lens' c_aNxZ Text
+ Puppet.Language: itype :: HasRIdentifier c_aNze => Lens' c_aNze Text
- Puppet.Language: linkInformation :: HasLinkInformation c_aOd9 => Lens' c_aOd9 LinkInformation
+ Puppet.Language: linkInformation :: HasLinkInformation c_aOeo => Lens' c_aOeo LinkInformation
- Puppet.Language: linkPos :: HasLinkInformation c_aOd9 => Lens' c_aOd9 PPosition
+ Puppet.Language: linkPos :: HasLinkInformation c_aOeo => Lens' c_aOeo PPosition
- Puppet.Language: linkType :: HasLinkInformation c_aOd9 => Lens' c_aOd9 LinkType
+ Puppet.Language: linkType :: HasLinkInformation c_aOeo => Lens' c_aOeo LinkType
- Puppet.Language: linkdst :: HasLinkInformation c_aOd9 => Lens' c_aOd9 RIdentifier
+ Puppet.Language: linkdst :: HasLinkInformation c_aOeo => Lens' c_aOeo RIdentifier
- Puppet.Language: linksrc :: HasLinkInformation c_aOd9 => Lens' c_aOd9 RIdentifier
+ Puppet.Language: linksrc :: HasLinkInformation c_aOeo => Lens' c_aOeo RIdentifier
- Puppet.Language: manifestPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Language: manifestPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Language: modulesPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Language: modulesPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Language: nativeTypeMethods :: HasNativeTypeMethods c_aYsx => Lens' c_aYsx NativeTypeMethods
+ Puppet.Language: nativeTypeMethods :: HasNativeTypeMethods c_aYtM => Lens' c_aYtM NativeTypeMethods
- Puppet.Language: puppetDirPaths :: HasPuppetDirPaths c_avEe => Lens' c_avEe PuppetDirPaths
+ Puppet.Language: puppetDirPaths :: HasPuppetDirPaths c_avFt => Lens' c_avFt PuppetDirPaths
- Puppet.Language: puppetFields :: HasNativeTypeMethods c_aYsx => Lens' c_aYsx (HashSet Text)
+ Puppet.Language: puppetFields :: HasNativeTypeMethods c_aYtM => Lens' c_aYtM (HashSet Text)
- Puppet.Language: puppetValidate :: HasNativeTypeMethods c_aYsx => Lens' c_aYsx NativeTypeValidate
+ Puppet.Language: puppetValidate :: HasNativeTypeMethods c_aYtM => Lens' c_aYtM NativeTypeValidate
- Puppet.Language: rIdentifier :: HasRIdentifier c_aNxZ => Lens' c_aNxZ RIdentifier
+ Puppet.Language: rIdentifier :: HasRIdentifier c_aNze => Lens' c_aNze RIdentifier
- Puppet.Language: ralias :: HasResource c_aNnl => Lens' c_aNnl (HashSet Text)
+ Puppet.Language: ralias :: HasResource c_aNoA => Lens' c_aNoA (HashSet Text)
- Puppet.Language: rattributes :: HasResource c_aNnl => Lens' c_aNnl (Container PValue)
+ Puppet.Language: rattributes :: HasResource c_aNoA => Lens' c_aNoA (Container PValue)
- Puppet.Language: resource :: HasResource c_aNnl => Lens' c_aNnl Resource
+ Puppet.Language: resource :: HasResource c_aNoA => Lens' c_aNoA Resource
- Puppet.Language: rid :: HasResource c_aNnl => Lens' c_aNnl RIdentifier
+ Puppet.Language: rid :: HasResource c_aNoA => Lens' c_aNoA RIdentifier
- Puppet.Language: rnode :: HasResource c_aNnl => Lens' c_aNnl NodeName
+ Puppet.Language: rnode :: HasResource c_aNoA => Lens' c_aNoA NodeName
- Puppet.Language: rpos :: HasResource c_aNnl => Lens' c_aNnl PPosition
+ Puppet.Language: rpos :: HasResource c_aNoA => Lens' c_aNoA PPosition
- Puppet.Language: rrelations :: HasResource c_aNnl => Lens' c_aNnl (HashMap RIdentifier (HashSet LinkType))
+ Puppet.Language: rrelations :: HasResource c_aNoA => Lens' c_aNoA (HashMap RIdentifier (HashSet LinkType))
- Puppet.Language: rscope :: HasResource c_aNnl => Lens' c_aNnl [CurContainerDesc]
+ Puppet.Language: rscope :: HasResource c_aNoA => Lens' c_aNoA [CurContainerDesc]
- Puppet.Language: rtags :: HasResource c_aNnl => Lens' c_aNnl (HashSet Text)
+ Puppet.Language: rtags :: HasResource c_aNoA => Lens' c_aNoA (HashSet Text)
- Puppet.Language: rvirtuality :: HasResource c_aNnl => Lens' c_aNnl Virtuality
+ Puppet.Language: rvirtuality :: HasResource c_aNoA => Lens' c_aNoA Virtuality
- Puppet.Language: templatesPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Language: templatesPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Language: testPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Language: testPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Language: wireCatalog :: HasWireCatalog c_aWBF => Lens' c_aWBF WireCatalog
+ Puppet.Language: wireCatalog :: HasWireCatalog c_aWCU => Lens' c_aWCU WireCatalog
- Puppet.Language: wireCatalogEdges :: HasWireCatalog c_aWBF => Lens' c_aWBF (Vector PuppetEdge)
+ Puppet.Language: wireCatalogEdges :: HasWireCatalog c_aWCU => Lens' c_aWCU (Vector PuppetEdge)
- Puppet.Language: wireCatalogNodename :: HasWireCatalog c_aWBF => Lens' c_aWBF NodeName
+ Puppet.Language: wireCatalogNodename :: HasWireCatalog c_aWCU => Lens' c_aWCU NodeName
- Puppet.Language: wireCatalogResources :: HasWireCatalog c_aWBF => Lens' c_aWBF (Vector Resource)
+ Puppet.Language: wireCatalogResources :: HasWireCatalog c_aWCU => Lens' c_aWCU (Vector Resource)
- Puppet.Language: wireCatalogTransactionUUID :: HasWireCatalog c_aWBF => Lens' c_aWBF Text
+ Puppet.Language: wireCatalogTransactionUUID :: HasWireCatalog c_aWCU => Lens' c_aWCU Text
- Puppet.Language: wireCatalogVersion :: HasWireCatalog c_aWBF => Lens' c_aWBF Text
+ Puppet.Language: wireCatalogVersion :: HasWireCatalog c_aWCU => Lens' c_aWCU Text
- Puppet.Parser: class HasHOLambdaCall c_a1m38
+ Puppet.Parser: class HasHOLambdaCall c_a1m4n
- Puppet.Parser: hOLambdaCall :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 HOLambdaCall
+ Puppet.Parser: hOLambdaCall :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n HOLambdaCall
- Puppet.Parser: hoLambdaExpr :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 (Vector Expression)
+ Puppet.Parser: hoLambdaExpr :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n (Vector Expression)
- Puppet.Parser: hoLambdaFunc :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 LambdaFunc
+ Puppet.Parser: hoLambdaFunc :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n LambdaFunc
- Puppet.Parser: hoLambdaLastExpr :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 (Maybe Expression)
+ Puppet.Parser: hoLambdaLastExpr :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n (Maybe Expression)
- Puppet.Parser: hoLambdaParams :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 LambdaParameters
+ Puppet.Parser: hoLambdaParams :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n LambdaParameters
- Puppet.Parser: hoLambdaStatements :: HasHOLambdaCall c_a1m38 => Lens' c_a1m38 (Vector Statement)
+ Puppet.Parser: hoLambdaStatements :: HasHOLambdaCall c_a1m4n => Lens' c_a1m4n (Vector Statement)
- Puppet.Runner: baseDir :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Runner: baseDir :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Runner: class HasPuppetDirPaths c_avEe
+ Puppet.Runner: class HasPuppetDirPaths c_avFt
- Puppet.Runner: manifestPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Runner: manifestPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Runner: modulesPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Runner: modulesPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Runner: prefExtFuncs :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Container ([PValue] -> InterpreterMonad PValue))
+ Puppet.Runner: prefExtFuncs :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Container ([PValue] -> InterpreterMonad PValue))
- Puppet.Runner: prefExternalmodules :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (HashSet Text)
+ Puppet.Runner: prefExternalmodules :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (HashSet Text)
- Puppet.Runner: prefExtraTests :: forall m_a3F1k. Lens' (Preferences m_a3F1k) Bool
+ Puppet.Runner: prefExtraTests :: forall m_a3GZr. Lens' (Preferences m_a3GZr) Bool
- Puppet.Runner: prefFactsDefault :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Container PValue)
+ Puppet.Runner: prefFactsDefault :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Container PValue)
- Puppet.Runner: prefFactsOverride :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Container PValue)
+ Puppet.Runner: prefFactsOverride :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Container PValue)
- Puppet.Runner: prefHieraPath :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Maybe FilePath)
+ Puppet.Runner: prefHieraPath :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Maybe FilePath)
- Puppet.Runner: prefIgnoredmodules :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (HashSet Text)
+ Puppet.Runner: prefIgnoredmodules :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (HashSet Text)
- Puppet.Runner: prefKnowngroups :: forall m_a3F1k. Lens' (Preferences m_a3F1k) [Text]
+ Puppet.Runner: prefKnowngroups :: forall m_a3GZr. Lens' (Preferences m_a3GZr) [Text]
- Puppet.Runner: prefKnownusers :: forall m_a3F1k. Lens' (Preferences m_a3F1k) [Text]
+ Puppet.Runner: prefKnownusers :: forall m_a3GZr. Lens' (Preferences m_a3GZr) [Text]
- Puppet.Runner: prefLogLevel :: forall m_a3F1k. Lens' (Preferences m_a3F1k) Priority
+ Puppet.Runner: prefLogLevel :: forall m_a3GZr. Lens' (Preferences m_a3GZr) Priority
- Puppet.Runner: prefNatTypes :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Container NativeTypeMethods)
+ Puppet.Runner: prefNatTypes :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Container NativeTypeMethods)
- Puppet.Runner: prefPDB :: forall m_a3F1k m_a3F6a. Lens (Preferences m_a3F1k) (Preferences m_a3F6a) (PuppetDBAPI m_a3F1k) (PuppetDBAPI m_a3F6a)
+ Puppet.Runner: prefPDB :: forall m_a3GZr m_a3H4h. Lens (Preferences m_a3GZr) (Preferences m_a3H4h) (PuppetDBAPI m_a3GZr) (PuppetDBAPI m_a3H4h)
- Puppet.Runner: prefPuppetPaths :: forall m_a3F1k. Lens' (Preferences m_a3F1k) PuppetDirPaths
+ Puppet.Runner: prefPuppetPaths :: forall m_a3GZr. Lens' (Preferences m_a3GZr) PuppetDirPaths
- Puppet.Runner: prefPuppetSettings :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Container Text)
+ Puppet.Runner: prefPuppetSettings :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Container Text)
- Puppet.Runner: prefRebaseFile :: forall m_a3F1k. Lens' (Preferences m_a3F1k) (Maybe FilePath)
+ Puppet.Runner: prefRebaseFile :: forall m_a3GZr. Lens' (Preferences m_a3GZr) (Maybe FilePath)
- Puppet.Runner: prefStrictness :: forall m_a3F1k. Lens' (Preferences m_a3F1k) Strictness
+ Puppet.Runner: prefStrictness :: forall m_a3GZr. Lens' (Preferences m_a3GZr) Strictness
- Puppet.Runner: puppetDirPaths :: HasPuppetDirPaths c_avEe => Lens' c_avEe PuppetDirPaths
+ Puppet.Runner: puppetDirPaths :: HasPuppetDirPaths c_avFt => Lens' c_avFt PuppetDirPaths
- Puppet.Runner: templatesPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Runner: templatesPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- Puppet.Runner: testPath :: HasPuppetDirPaths c_avEe => Lens' c_avEe FilePath
+ Puppet.Runner: testPath :: HasPuppetDirPaths c_avFt => Lens' c_avFt FilePath
- PuppetDB: class HasNodeInfo c_a1XdJ
+ PuppetDB: class HasNodeInfo c_a1XeY
- PuppetDB: nodeInfo :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ NodeInfo
+ PuppetDB: nodeInfo :: HasNodeInfo c_a1XeY => Lens' c_a1XeY NodeInfo
- PuppetDB: nodeInfoCatalogT :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ (Maybe UTCTime)
+ PuppetDB: nodeInfoCatalogT :: HasNodeInfo c_a1XeY => Lens' c_a1XeY (Maybe UTCTime)
- PuppetDB: nodeInfoDeactivated :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ Bool
+ PuppetDB: nodeInfoDeactivated :: HasNodeInfo c_a1XeY => Lens' c_a1XeY Bool
- PuppetDB: nodeInfoFactsT :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ (Maybe UTCTime)
+ PuppetDB: nodeInfoFactsT :: HasNodeInfo c_a1XeY => Lens' c_a1XeY (Maybe UTCTime)
- PuppetDB: nodeInfoName :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ NodeName
+ PuppetDB: nodeInfoName :: HasNodeInfo c_a1XeY => Lens' c_a1XeY NodeName
- PuppetDB: nodeInfoReportT :: HasNodeInfo c_a1XdJ => Lens' c_a1XdJ (Maybe UTCTime)
+ PuppetDB: nodeInfoReportT :: HasNodeInfo c_a1XeY => Lens' c_a1XeY (Maybe UTCTime)
Files
- CHANGELOG +10/−0
- README.md +1/−1
- language-puppet.cabal +27/−25
- progs/yera.hs +5/−5
- src/Erb/Parser.hs +3/−1
- src/Hiera/Server.hs +107/−52
- src/Puppet/Interpreter/Helpers.hs +6/−0
- src/Puppet/Interpreter/IO.hs +21/−21
- src/Puppet/Interpreter/Resolve.hs +39/−12
- src/Puppet/Interpreter/Types.hs +1/−1
- src/Puppet/Runner/Erb.hs +3/−3
- src/Puppet/Runner/Pure.hs +2/−2
- src/Puppet/Runner/Stdlib.hs +2/−1
- src/PuppetDB/Remote.hs +5/−2
- src/XPrelude/Extra.hs +4/−0
- tests/ErbSpec.hs +3/−0
- tests/HieraSpec.hs +199/−51
- tests/Interpreter/Function/LookupSpec.hs +5/−0
- tests/hiera/interpolate/config/hiera.yaml +14/−0
- tests/hiera/interpolate/config/hiera_iplm_hiera.yaml +6/−0
- tests/hiera/interpolate/config/hiera_iplm_hiera_bad.yaml +5/−0
- tests/hiera/interpolate/data/bad_interpolation.yaml +9/−0
- tests/hiera/interpolate/data/complex.yaml +12/−0
- tests/hiera/interpolate/data/dotted_keys.yaml +43/−0
- tests/hiera/interpolate/data/empty_interpolation.yaml +13/−0
- tests/hiera/interpolate/data/niltest.yaml +2/−0
- tests/hiera/interpolate/data/recursive.yaml +3/−0
- tests/hiera/interpolate/data/weird_keys.yaml +12/−0
- tests/hiera/production.yaml +6/−0
CHANGELOG view
@@ -1,5 +1,13 @@ language-puppet (1.4.5) artful; urgency=medium + * Add the `reduce` function.+ * Change A hiera lookup using an unknown key will throw an error.+ * Implement `alias` in hiera files.+ * Fix #277 (hiera lookup in multiple layers)+ * Allow servant 0.16++ -- Pierre Radermecker <pierrer@pi3r.be> Mo, 17 June 2019 16:12:48 +0100+ language-puppet (1.4.4) artful; urgency=medium * Add the `deep_merge` stdlib function.@@ -22,6 +30,8 @@ language-puppet (1.4.2) artful; urgency=medium * Bump upper version bounds for some haskell packages++ -- Pierre Radermecker <pierrer@pi3r.be> Wed, 20 Feb 2019 21:32:48 +0100 language-puppet (1.4.1) artful; urgency=medium
README.md view
@@ -15,7 +15,7 @@ **Install with nix:** ```-nix-env -i -f https://github.com/bartavelle/language-puppet/tarball/v1.4.3+nix-env -i -f https://github.com/bartavelle/language-puppet/tarball/v1.4.5 ``` (replace `1.4.3` with any commit ref or tag).
language-puppet.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: language-puppet-version: 1.4.4+version: 1.4.5 synopsis: Tools to parse and evaluate the Puppet DSL. description: This is a set of tools that is supposed to fill all your Puppet needs : syntax checks, catalog compilation, PuppetDB queries, simulation of complex interactions between nodes, Puppet master replacement, and more ! homepage: http://lpuppet.banquise.net/@@ -16,13 +16,15 @@ cabal-version: >=1.8 bug-reports: https://github.com/bartavelle/language-puppet/issues -Tested-With: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4+Tested-With: GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.4 extra-source-files: CHANGELOG README.md HLint.hs tests/hiera/*.yaml+ tests/hiera/interpolate/config/*.yaml+ tests/hiera/interpolate/data/*.yaml tests/hiera/*.com.json tests/Parser/lexer/*.pp @@ -96,49 +98,49 @@ extensions: OverloadedStrings, BangPatterns, LambdaCase, NoImplicitPrelude, FlexibleContexts, FlexibleInstances ghc-options: -Wall -funbox-strict-fields -- ghc-prof-options: -auto-all -caf-all- build-depends: aeson >= 0.8+ build-depends: aeson >= 1.0.0.0 && < 1.5 , ansi-wl-pprint >= 0.6.8 , attoparsec >= 0.12- , base >=4.9 && < 5+ , base >=4.9 && < 5 , base16-bytestring == 0.1.*- , bytestring+ , bytestring < 0.11 , case-insensitive == 1.2.* , containers >= 0.5 && < 0.7 , cryptonite >= 0.6 , directory >= 1.2 && < 1.4 , filecache >= 0.2.9 && < 0.5 , filepath >= 1.4- , formatting+ , formatting < 7 , hashable == 1.2.*- , http-api-data >= 0.2 && < 0.5- , http-client >= 0.4.30 && < 0.7- , hruby >= 0.3.2 && < 0.4+ , http-api-data >= 0.2 && < 0.5+ , http-client >= 0.4.30 && < 0.7+ , hruby >= 0.3.2 && < 0.4 , hslogger == 1.2.* , lens >= 4.12 && < 5 , lens-aeson >= 1.0 , megaparsec >= 7 && < 8- , memory >= 0.7+ , memory >= 0.14 && < 0.15 , mtl >= 2.2.1 && < 2.3 , operational >= 0.2.3 && < 0.3 , parsec == 3.1.* , parser-combinators == 1.* , pcre-utils >= 0.1.7 && < 0.2- , protolude >= 0.2+ , protolude >= 0.2 && < 0.3 , random , regex-pcre-builtin >= 0.94.4- , scientific >= 0.2 && < 0.4- , servant >= 0.9 && < 0.16- , servant-client >= 0.9 && < 0.16+ , scientific >= 0.2 && < 0.4+ , servant >= 0.9 && < 0.17+ , servant-client >= 0.9 && < 0.17 , split == 0.2.*- , stm >= 2.4 && < 2.6+ , stm >= 2.4 && < 2.6 , strict-base-types >= 0.3- , text >= 0.11- , time >= 1.5 && < 2- , transformers >= 0.4 && < 0.6- , unix >= 2.7 && < 2.8+ , text >= 0.11 && < 1.3+ , time >= 1.5 && < 2+ , transformers >= 0.4 && < 0.6+ , unix >= 2.7 && < 2.8 , unordered-containers == 0.2.*- , vector >= 0.10- , yaml >= 0.8.31 && < 0.12+ , vector >= 0.10 && < 0.13+ , yaml >= 0.8.31 && < 0.12 Test-Suite spec hs-source-dirs: tests type: exitcode-stdio-1.0@@ -147,13 +149,13 @@ build-depends: base , Glob , hslogger- , hspec+ , hspec >= 2.0 && < 3.0 , hspec-megaparsec , megaparsec , language-puppet- , lens- , mtl- , scientific+ , lens >= 4.12 && < 5+ , mtl >= 2.2.1 && < 2.3+ , scientific >= 0.2 && < 0.4 , strict-base-types , text , temporary
progs/yera.hs view
@@ -5,12 +5,12 @@ import XPrelude hiding (option) -import qualified Data.Either.Strict as S import qualified Data.HashMap.Strict as Map import qualified Data.List as List import Options.Applicative import Hiera.Server+import Puppet.Language (PValue(..)) data Config = Config@@ -42,7 +42,7 @@ main = do Config fp query qtype vars <- execParser configInfo hiera <- startHiera "yera" fp- hiera (Map.fromList vars) (toS query) qtype >>= \case- S.Left rr -> panic (show rr)- S.Right Nothing -> die "no match"- S.Right (Just res) -> print (pretty res)+ runExceptT (hiera (PString <$> Map.fromList vars) (toS query) qtype) >>= \case+ Left rr -> panic (show rr)+ Right Nothing -> die "no match"+ Right (Just res) -> print (pretty res)
src/Erb/Parser.hs view
@@ -101,8 +101,10 @@ stringLiteral = Value `fmap` (doubleQuoted <|> singleQuoted) doubleQuoted :: Parser Value-doubleQuoted = Interpolable <$> between (char '"') (char '"') quoteInternal+doubleQuoted = simplify <$> between (char '"') (char '"') quoteInternal where+ simplify [Value x] = x+ simplify x = Interpolable x quoteInternal = many (basicContent <|> interpvar <|> escaped) escaped = char '\\' >> (Value . Literal . Text.singleton) `fmap` anyChar basicContent = (Value . Literal . Text.pack) `fmap` many1 (noneOf "\"\\#")
src/Hiera/Server.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PatternGuards #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-}@@ -17,25 +18,30 @@ , HieraQueryType (..) , readQueryType , HieraQueryFunc+ , varSplitter+ , mergeWith ) where import XPrelude import Data.Aeson-import qualified Data.Aeson as Aeson+import qualified Data.Aeson as Aeson import Data.Aeson.Lens-import qualified Data.Attoparsec.Text as AT-import qualified Data.ByteString.Lazy as BS-import qualified Data.Either.Strict as S-import qualified Data.FileCache as Cache-import qualified Data.List as List-import Data.String (fromString)-import qualified Data.Text as Text-import qualified Data.Vector as Vector-import qualified Data.Yaml as Yaml-import qualified System.Directory as Directory-import qualified System.FilePath as FilePath-import System.FilePath.Lens (directory)+import qualified Data.Attoparsec.Text as AT+import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString.Lazy.Char8 as BS8+import qualified Data.Either.Strict as S+import qualified Data.FileCache as Cache+import qualified Data.List as List+import Data.String (fromString)+import qualified Data.Text as Text+import qualified Data.Vector as Vector+import qualified Data.Yaml as Yaml+import qualified System.Directory as Directory+import qualified System.FilePath as FilePath+import System.FilePath.Lens (directory)+import Text.Megaparsec (parse, sepBy1, Parsec, satisfy)+import Text.Megaparsec.Char (char) import Puppet.Language @@ -60,10 +66,10 @@ _ -> Nothing -- | The type of the Hiera API function associated to given hierarchy.-type HieraQueryFunc m = Container Text -- ^ Scope: all variables that Hiera can interpolate (the top level ones are prefixed with '::')+type HieraQueryFunc m = Container PValue -- ^ Scope: all variables that Hiera can interpolate (the top level ones are prefixed with '::') -> Text -- ^ The query -> HieraQueryType- -> m (S.Either PrettyError (Maybe PValue))+ -> ExceptT PrettyError m (Maybe PValue) data Backend = YamlBackend FilePath@@ -84,11 +90,23 @@ { getInterpolableHieraString :: [HieraStringPart] } deriving (Show) -resolveString :: Container Text -> InterpolableHieraString -> Maybe Text+varSplitter :: Text -> [Text]+varSplitter v =+ case parse (vpart `sepBy1` char '.' :: Parsec Void Text [Text]) "dummy" v of+ Left _ -> [v]+ Right lst -> lst+ where+ vpart = squotev <|> dquotev <|> rawv+ rawv = Text.pack <$> some (satisfy (/= '.'))+ -- TODO, escapes+ squotev = Text.pack <$> (char '\'' *> some (satisfy (/= '\'')) <* char '\'')+ dquotev = Text.pack <$> (char '"' *> some (satisfy (/= '"')) <* char '"')++resolveString :: Container PValue -> InterpolableHieraString -> Maybe Text resolveString vars = fmap Text.concat . mapM resolve . getInterpolableHieraString where resolve (HPString x) = Just x- resolve (HPVariable v) = vars ^? ix v+ resolve (HPVariable v) = vars ^? ix v . _PString instance FromJSON InterpolableHieraString where parseJSON (String s) = case parseInterpolableString s of@@ -101,7 +119,7 @@ interpolableString = AT.many1 (fmap HPString rawPart <|> fmap HPVariable interpPart) where rawPart = AT.takeWhile1 (/= '%')- interpPart = AT.string "%{" *> AT.takeWhile1 (/= '}') <* AT.char '}'+ interpPart = AT.string "%{" *> AT.takeWhile (/= '}') <* AT.char '}' parseInterpolableString :: Text -> Either String [HieraStringPart] parseInterpolableString = AT.parseOnly interpolableString@@ -113,7 +131,7 @@ } deriving (Show) data QRead = QRead- { _qvars :: Container Text+ { _qvars :: Container PValue , _qtype :: HieraQueryType , _qhier :: [Value] }@@ -179,13 +197,14 @@ Left ex -> panic (show ex) Right cfg@HieraConfigFile{..} -> do logInfoStr ("Detect a hiera " <> layer <> " configuration format in " <> fp <> " at version " <> show _version)- cache <- Cache.newFileCache- pure (query cfg fp cache)+ query cfg fp <$> Cache.newFileCache -- | A dummy hiera function that will be used when hiera is not detected. dummyHiera :: Monad m => HieraQueryFunc m-dummyHiera _ _ _ = return $ S.Right Nothing+dummyHiera _ _ _ = pure Nothing +exceptt :: Applicative m => Except r a -> ExceptT r m a+exceptt = ExceptT . pure . runExcept query :: HieraConfigFile -> FilePath -> Cache -> HieraQueryFunc IO query HieraConfigFile {_version, _backends, _hierarchy} fp cache vars hquery qt = do@@ -194,14 +213,14 @@ mhierarchy <- resolveString vars <$> _hierarchy Just h <- [mhierarchy] backend <- _backends- let decodeInfo :: (FilePath -> IO (S.Either String Value), String, String)+ let decodeInfo :: (FilePath -> IO (Either String Value), String, String) decodeInfo = case backend of- JsonBackend dir -> (fmap (strictifyEither . Aeson.eitherDecode') . BS.readFile , dir, ".json")- YamlBackend dir -> (fmap (strictifyEither . (_Left %~ show)) . Yaml.decodeFileEither, dir, ".yaml")+ JsonBackend dir -> (fmap Aeson.eitherDecode' . BS.readFile , dir, ".json")+ YamlBackend dir -> (fmap (_Left %~ show) . Yaml.decodeFileEither, dir, ".yaml") pure (decodeInfo, toS h) -- step 2, read all the files, returning a raw data structure- mvals <- forM searchin $ \((decodefunction, datadir, extension), h) -> do+ mvals <- liftIO $ forM searchin $ \((decodefunction, datadir, extension), h) -> do let extension' = if snd (FilePath.splitExtension h) == ".yaml" then "" else extension@@ -210,45 +229,68 @@ '/' : _ -> mempty _ -> fp ^. directory <> "/" querycache = do- efilecontent <- Cache.query cache filename (decodefunction filename)+ efilecontent <- Cache.query cache filename (strictifyEither <$> decodefunction filename) case efilecontent of S.Left r -> do logWarningStr $ "Hiera: error when reading file " <> filename <> ": "<> r pure Nothing- S.Right val -> do- pure (Just val)+ S.Right val -> pure (Just val) ifM (Directory.doesFileExist filename) querycache (pure Nothing) let vals = catMaybes mvals -- step 3, query through all the results- logDebugStr ("Looking up '" <> toS hquery <> "' with backends " <> List.unwords (fmap show _backends ))- return (strictifyEither $ runReader (runExceptT (recursiveQuery hquery [])) (QRead vars qt vals))+ liftIO $ logDebugStr ("Looking up '" <> toS hquery <> "' with backends " <> List.unwords (fmap show _backends ))+ exceptt $ runReaderT (recursiveQuery hquery []) (QRead vars qt vals) -type QM a = ExceptT PrettyError (Reader QRead) a+type QM a = ReaderT QRead (Except PrettyError) a checkLoop :: Text -> [Text] -> QM () checkLoop x xs = when (x `elem` xs) (throwError ("Loop in hiera: " <> fromString (Text.unpack (Text.intercalate ", " (x:xs))))) +-- a helper function that removes prefix and suffix+textBetween :: Text -- ^ prefix+ -> Text -- ^ suffix+ -> Text+ -> Maybe Text+textBetween pr su = Text.stripPrefix pr >=> Text.stripSuffix su+ recursiveQuery :: Text -> [Text] -> QM (Maybe PValue) recursiveQuery curquery prevqueries = do- checkLoop curquery prevqueries- rawlookups <- mapMaybe (preview (key curquery)) <$> view qhier- lookups <- mapM (resolveValue (curquery : prevqueries)) rawlookups- case lookups of- [] -> return Nothing- (x:xs) -> do+ let (varname:allkeys) = varSplitter curquery+ checkLoop varname prevqueries+ rawlookups <- mapMaybe (preview (key varname)) <$> view qhier+ let lookupKeys keys v =+ case keys of+ [] -> pure v+ k:ks ->+ case v of+ Object hs ->+ case hs ^? ix k of+ Nothing -> Nothing+ Just v' -> lookupKeys ks v'+ _ -> Nothing+ rlookups <- mapM (resolveValue (varname : prevqueries)) rawlookups+ let lookups = mapMaybe (lookupKeys allkeys) rlookups+ case traverse Aeson.fromJSON lookups of+ Aeson.Error rr -> throwError ("Something horrible happened in recursiveQuery: " <> fromString rr)+ Aeson.Success [] ->+ if null rlookups+ then return Nothing+ else throwError ("Could not lookup " <> fromString (Text.unpack curquery) <> " in " <> PrettyError (list (map (fromString . BS8.unpack . encode) rlookups)) )+ Aeson.Success (x:xs) -> do qt <- view qtype- let evalue = foldM (mergeWith qt) x xs- case Aeson.fromJSON <$> evalue of- Left _ -> return Nothing- Right (Aeson.Success o) -> return o- Right (Aeson.Error rr) -> throwError ("Something horrible happened in recursiveQuery: " <> fromString rr)+ Just <$> foldM (mergeWith qt) x xs resolveValue :: [Text] -> Value -> QM Value resolveValue prevqueries value = case value of+ String t | Just alias <- Text.stripPrefix "%{alias('" t >>= Text.stripSuffix "')}" -> do+ mr <- recursiveQuery alias (("alias:" <> alias) : prevqueries)+ case mr of+ Nothing -> throwError ("Could not alias " <> fromString (Text.unpack alias))+ Just r -> pure (toJSON r) String t -> String <$> resolveText prevqueries t Array arr -> Array <$> mapM (resolveValue prevqueries) arr Object hh -> Object <$> mapM (resolveValue prevqueries) hh@@ -264,29 +306,42 @@ resolveStringPart prevqueries sp = case sp of HPString s -> return s+ HPVariable "" -> return "" HPVariable varname -> do- let varsolve = fmap PString . preview (ix varname) <$> view qvars- r <- case Text.stripPrefix "lookup('" varname >>= Text.stripSuffix "')" of+ let rc vars val =+ case vars of+ [] -> pure val+ v:vs -> case val of+ PHash m -> m ^? ix v >>= rc vs+ _ -> Nothing+ extractFunction txt = textBetween (txt <> "('") "')" varname+ <|> textBetween (txt <> "(\"") "\")" varname+ r <- case extractFunction "lookup" <|> extractFunction "hiera" <|> extractFunction "alias" of Just lk -> recursiveQuery lk prevqueries- Nothing -> varsolve+ Nothing -> do+ vmap <- view qvars+ let mvar:svars = varSplitter varname+ pure (vmap ^? ix mvar >>= rc svars) case r of Just (PString v) -> return v- _ -> return mempty+ Just (PNumber s) -> pure (scientific2text s)+ Just pvalue -> throwError (PrettyError ("Variable lookup for " <> fromString (Text.unpack varname) <> " did not return a string, but " <> pretty pvalue))+ _ -> throwError ("Could not lookup variable " <> fromString (Text.unpack varname)) -mergeWith :: HieraQueryType -> Value -> Value -> Either PrettyError Value+mergeWith :: MonadError PrettyError m => HieraQueryType -> PValue -> PValue -> m PValue mergeWith qt cur new = case qt of QFirst -> return cur QUnique -> let getArray x = case x of- Array array -> Vector.toList array+ PArray array -> Vector.toList array _ -> [x] curarray = getArray cur newarray = getArray new in case new of- Object _ -> throwError "Tried to merge a hash"- _ -> return (Array (Vector.fromList (List.nub (curarray ++ newarray))))+ PHash _ -> throwError "Tried to merge a hash"+ _ -> return (PArray (Vector.fromList (List.nub (curarray ++ newarray)))) QHash -> case (cur, new) of- (Object curh, Object newh) -> return (Object (curh <> newh))+ (PHash curh, PHash newh) -> return (PHash (curh <> newh)) _ -> throwError (PrettyError ("Tried to merge things that are not hashes: " <> ppline (show cur) <+> ppline (show new))) QDeep{} -> throwError "deep queries not supported"
src/Puppet/Interpreter/Helpers.hs view
@@ -152,6 +152,12 @@ isExternal = singleton . IsExternalModule . List.head . Text.splitOn "::" -- Logging --+error :: MonadWriter InterpreterWriter m => Doc -> m ()+error d = tell [Log.ERROR :!: d]++critical :: MonadWriter InterpreterWriter m => Doc -> m ()+critical d = tell [Log.CRITICAL :!: d]+ warn :: MonadWriter InterpreterWriter m => Doc -> m () warn d = tell [Log.WARNING :!: d]
src/Puppet/Interpreter/IO.hs view
@@ -69,7 +69,8 @@ GetNativeTypes -> runInstr (r ^. readerNativeTypes) ErrorThrow d -> return (Left d, s, mempty) GetNodeName -> runInstr (r ^. readerNodename)- HieraQuery scps q t -> canFail (queryHiera (r ^. readerHieraQuery) scps q t)+ HieraQuery scps q t ->+ runExceptT (queryHiera (r ^. readerHieraQuery) scps q t) >>= either thpe runInstr PDBInformation -> pdbInformation pdb >>= runInstr PDBReplaceCatalog w -> canFailX (replaceCatalog pdb w) PDBReplaceFacts fcts -> canFailX (replaceFacts pdb fcts)@@ -91,25 +92,24 @@ Left rr -> interpretMonad r s (ahandle rr >>= k) Right x -> logStuff w (interpretMonad r s' (k x)) - -- query all hiera layers-queryHiera :: Monad m => HieraQueryLayers m -> Container Text -> Text -> HieraQueryType -> m (S.Either PrettyError (Maybe PValue))+queryHiera :: Monad m+ => HieraQueryLayers m+ -> Container PValue+ -> Text+ -> HieraQueryType+ -> ExceptT PrettyError m (Maybe PValue) queryHiera layers scps q t = do- val0 <- (layers^.globalLayer) scps q t- case val0 of- S.Right Nothing -> do- val1 <- (layers ^.environmentLayer) scps q t- case val1 of- S.Right Nothing -> query_modlayer- _ -> pure val1- _ -> pure val0- where- query_modlayer = do- let- modname =- case Text.splitOn "::" (Text.dropWhile (==':') q) of- [] -> Nothing- [_] -> Nothing- (m:_) -> Just m- layer = modname >>= (\n -> layers ^.moduleLayer.at n)- maybe (pure $ S.Right Nothing) (\hq -> hq scps q t) layer+ eglobal <- (layers^.globalLayer) scps q t+ eenvironment <- (layers ^.environmentLayer) scps q t+ let modname =+ case Text.splitOn "::" (Text.dropWhile (==':') q) of+ [] -> Nothing+ [_] -> Nothing+ (m:_) -> Just m+ layer = modname >>= (\n -> layers ^.moduleLayer.at n)+ emodle <- maybe (pure Nothing) (\hq -> hq scps q t) layer+ case catMaybes [eglobal, eenvironment, emodle] of+ [] -> pure Nothing+ x:xs -> Just <$> foldM (mergeWith t) x xs+
src/Puppet/Interpreter/Resolve.hs view
@@ -93,12 +93,17 @@ runHiera q t = do -- We need to merge the current scope with the top level scope scps <- use scopes- ctx <- getScopeName- let getV scp = mapMaybe toStr $ HM.toList $ fmap (view (_1 . _1)) (scps ^. ix scp . scopeVariables)- toStr (k,v) = fmap (k,) (preview _PString v)- toplevels = map (_1 %~ ("::" <>)) $ getV "::"- locals = getV ctx- vars = HM.fromList (toplevels <> locals)+ curscopes <- use curScope+ let getV scp = HM.toList $ fmap (view (_1 . _1)) (scps ^. ix scp . scopeVariables)+ vars = HM.unions $ do+ curscp <- curscopes+ let sname = scopeName curscp+ curv = getV sname+ prefixVarname vname =+ case curscp of+ ContRoot -> "::" <> vname+ _ -> sname <> "::" <> vname+ [HM.fromList curv, HM.fromList (map (_1 %~ prefixVarname) curv)] Operational.singleton (HieraQuery vars q t) -- | The implementation of all lookup functions@@ -108,7 +113,7 @@ qs <- resolvePValueString q runHiera qs qt >>= \case Just p -> case dt of- Just dt' | not (datatypeMatch dt' p) -> throwPosError "Datatype mismatched"+ Just dt' | not (datatypeMatch dt' p) -> throwPosError ("Datatype mismatched :" <+> pretty dt' <+> "/" <+> pretty p) _ -> pure p Nothing -> case df of Just d -> pure d@@ -331,10 +336,8 @@ case (ra, rb) of (PArray ha, v) -> pure (PArray (V.snoc ha v)) _ -> integerOperation a b (\x -> shiftL x . fromIntegral)-resolveExpression a@(FunctionApplication e (Terminal (UHOLambdaCall hol))) = do- unless (null (hol ^. hoLambdaExpr))- (throwPosError ("You can't combine chains of higher order functions (with .) and giving them parameters, in:" <+> pretty a))- resolveValue (UHOLambdaCall (hol & hoLambdaExpr .~ V.singleton e))+resolveExpression (FunctionApplication e (Terminal (UHOLambdaCall hol))) =+ resolveValue (UHOLambdaCall (hol & hoLambdaExpr <>~ V.singleton e)) resolveExpression (FunctionApplication _ x) = throwPosError ("Expected function application here, not" <+> pretty x) resolveExpression (Negate x) = PNumber . negate <$> resolveExpressionNumber x @@ -566,7 +569,7 @@ resolveFunction' "hiera_hash" [q,d,o] = hieraCall QHash q (Just d) Nothing (Just o) resolveFunction' "lookup" [q] = hieraCall QFirst q Nothing Nothing Nothing resolveFunction' "lookup" [q, PType dt] = hieraCall QFirst q Nothing (Just dt) Nothing-resolveFunction' "lookup" [q, PType dt, PString qt, def] = do+resolveFunction' "lookup" [q, PType dt, PString qt, def] = case readQueryType qt of Nothing -> throwPosError ("Unknown merge strategy " <> ppline qt) Just qt' -> hieraCall qt' q (Just def) (Just dt) Nothing@@ -797,6 +800,30 @@ PArray ar -> pure $ PArray $ V.map fst $ V.filter snd $ V.zip ar (V.fromList res) PHash hh -> pure $ PHash $ HM.fromList $ map fst $ filter snd $ zip (HM.toList hh) res x -> throwPosError ("Can't iterate on this data type:" <+> pretty x)+ LambdaFunc "reduce" ->+ case hol ^.. hoLambdaExpr . folded of+ [zero', foldable'] -> do+ zero'' <- resolveExpression zero'+ foldable'' <- resolveExpression foldable'+ (accname, curname) <- case hol ^.. hoLambdaParams . folded of+ [an, cn] -> pure (an, cn)+ _ -> throwPosError ("Reduce requires two parameters in its block expression, in" <+> pretty hol)+ let runStep acc cur = do+ accName <- mCheckType acc accname+ curName <- mCheckType cur curname+ runblock [(accName, acc), (curName, cur)]+ mCheckType vl (LambdaParam mt nm) = do+ forM_ mt $ \ut -> do+ t <- resolveDataType ut+ checkMatch t vl+ pure nm+ case foldable'' of+ PArray ar -> foldM runStep zero'' ar+ PHash hs -> foldM runStep zero'' $ do+ (k,v) <- HM.toList hs+ return (PArray (V.fromList [PString k, v]))+ x -> throwPosError ("Can't iterate on this data type:" <+> pretty x)+ _ -> throwPosError ("Reduce requires two arguments and a lambda block, in" <+> pretty hol) x -> throwPosError ("This type of lambda function is not supported yet by language-puppet!" <+> pretty x) -- | Checks that a value matches a puppet datatype
src/Puppet/Interpreter/Types.hs view
@@ -238,7 +238,7 @@ ExternalFunction :: Text -> [PValue] -> InterpreterInstr PValue Facts :: InterpreterInstr (Container PValue) GetNodeName :: InterpreterInstr Text- HieraQuery :: Container Text -> Text -> HieraQueryType -> InterpreterInstr (Maybe PValue)+ HieraQuery :: Container PValue -> Text -> HieraQueryType -> InterpreterInstr (Maybe PValue) GetCurrentCallStack :: InterpreterInstr [String] IsIgnoredModule :: Text -> InterpreterInstr Bool IsExternalModule :: Text -> InterpreterInstr Bool
src/Puppet/Runner/Erb.hs view
@@ -128,7 +128,7 @@ Left err -> do let !msg = "At " <> showPPos'(intpstate^.curPos) <> " the evaluation of template '" <> template_src <> "' failed. " <> show err -- if the haskell evaluation fails the ruby one will fallback. It is likely that the reason for the failure is a real template issue.- logCriticalStr msg+ logErrorStr msg measure mstats ("ruby efail - " <> toS template_src) $ mkSafe $ computeTemplateWRuby srcinfo curcontext variables intpstate intpreader traceEventIO ("STOP template " <> template_src) pure o@@ -136,7 +136,7 @@ getRubyScriptPath :: String -> IO String getRubyScriptPath rubybin = do let checkpath :: FilePath -> IO FilePath -> IO FilePath- checkpath fp nxt = do+ checkpath fp nxt = ifM (fileExist fp) (pure fp) nxt@@ -200,7 +200,7 @@ contentinfo <- case fileinfo of Filename fname -> FR.toRuby (Text.pack fname) Inline _ -> FR.toRuby ("-" :: Text)- let withBinding f = do+ let withBinding f = FR.safeMethodCall "ErbBinding" "new" [rscp,rvariables,rstt,rrdr,contentinfo] >>= \case Left x -> pure (Left x) Right v -> do
src/Puppet/Runner/Pure.hs view
@@ -78,8 +78,8 @@ mempty where pure_hiera :: HieraQueryFunc Identity- pure_hiera _ _ _ = pure (S.Right hiera)- hieradummy = HieraQueryLayers pure_hiera pure_hiera mempty+ pure_hiera _ _ _ = pure hiera+ hieradummy = HieraQueryLayers pure_hiera (\_ _ _ -> pure Nothing) mempty getstatementdummy tlt n = return $ case HM.lookup (tlt,n) sttmap of Just x -> S.Right x Nothing -> S.Left "Can't get statement"
src/Puppet/Runner/Stdlib.hs view
@@ -22,6 +22,7 @@ import qualified System.FilePath as FilePath import Puppet.Interpreter+import Puppet.Interpreter.Helpers -- | Contains the implementation of the StdLib functions. stdlibFunctions :: Container ( [PValue] -> InterpreterMonad PValue )@@ -241,7 +242,7 @@ "encode" -> return (B16.encode b) "decode" -> case B16.decode b of (x, "") -> return x- _ -> throwPosError ("base64(): could not decode" <+> pretty pb)+ _ -> error ("base64(): could not decode" <+> pretty pb) *> pure mempty a -> throwPosError ("base64(): the first argument must be either 'encode' or 'decode', not" <+> ppline a) pure $ PString (decodeUtf8 r) base64 _ = throwPosError "base64(): Expects 2 arguments"
src/PuppetDB/Remote.hs view
@@ -16,7 +16,6 @@ import Puppet.Language import PuppetDB.Core - type PDBAPIv3 = "nodes" :> QueryParam "query" (Query NodeField) :> Get '[JSON] [NodeInfo] :<|> "nodes" :> Capture "resourcename" Text :> "resources" :> QueryParam "query" (Query ResourceField) :> Get '[JSON] [Resource] :<|> "facts" :> QueryParam "query" (Query FactField) :> Get '[JSON] [FactInfo]@@ -32,6 +31,10 @@ mkClientEnv = ClientEnv #endif +#if !MIN_VERSION_servant_client(0,16,0)+#define ClientError ServantError+#endif+ -- | Given an URL (ie. @http://localhost:8080@), will return an incomplete 'PuppetDBAPI'. pdbConnect :: Manager -> String -> IO (Either PrettyError (PuppetDBAPI IO)) pdbConnect mgr url = do@@ -54,5 +57,5 @@ sgetResources :: Maybe (Query ResourceField) -> ClientM [Resource] (sgetNodes :<|> sgetNodeResources :<|> sgetFacts :<|> sgetResources) = client api - prettyError :: IO (Either ServantError b) -> ExceptT PrettyError IO b+ prettyError :: IO (Either ClientError b) -> ExceptT PrettyError IO b prettyError = ExceptT . fmap (_Left %~ PrettyError . pplines . show)
src/XPrelude/Extra.hs view
@@ -19,6 +19,7 @@ , logWarning , logWarningStr , logError+ , logErrorStr , logCritical , logCriticalStr ) where@@ -121,6 +122,9 @@ logError :: Text -> IO () logError = Log.errorM "language-puppet" . toS++logErrorStr :: String -> IO ()+logErrorStr = Log.errorM "language-puppet" logCritical :: Text -> IO () logCritical = Log.criticalM "language-puppet" . toS
tests/ErbSpec.hs view
@@ -28,6 +28,9 @@ , ("<%= scope.lookupvar('::fqdn') %>", [ Puts (Value (Literal "")) , Puts (ScopeObject (Value (Literal "::fqdn"))) , Puts(Value (Literal ""))])+ , ("<%= scope.lookupvar(\"::fqdn\") %>", [ Puts (Value (Literal ""))+ , Puts (ScopeObject (Value (Literal "::fqdn")))+ , Puts(Value (Literal ""))]) ] resolvetests :: [([RubyStatement], Text)]
tests/HieraSpec.hs view
@@ -1,9 +1,7 @@-{-# LANGUAGE QuasiQuotes #-} module HieraSpec(spec) where import XPrelude -import qualified Data.Either.Strict as S import qualified Data.HashMap.Strict as HM import qualified Data.Vector as Vector import qualified System.Log.Logger as Log@@ -12,69 +10,219 @@ import Hiera.Server import Puppet.Language -checkOutput v (S.Right x) = x `shouldBe` v-checkOutput _ (S.Left rr) = expectationFailure (show rr)+checkOutput :: (Eq a, Show rr, Show a) => a -> Either rr a -> Expectation+checkOutput v (Right x) = x `shouldBe` v+checkOutput _ (Left rr) = expectationFailure (show rr) +checkFail :: (Show a) => Either rr a -> Expectation+checkFail (Right v) = expectationFailure ("Should have failed, but returned: " ++ show v)+checkFail _ = return ()++fqdn :: Text fqdn = "node.com"++config_v3 :: FilePath config_v3 = "./tests/hiera/hiera-v3.yaml"++config_v5 :: FilePath config_v5 = "./tests/hiera/hiera-v5.yaml" +configInterpolate :: FilePath+configInterpolate = "./tests/hiera/interpolate/config/hiera.yaml"++vars :: HM.HashMap Text PValue vars = HM.fromList [ ("::environment", "production")- , ("::fqdn" , fqdn)+ , ("::fqdn" , PString fqdn) ]++users :: HM.HashMap Text PValue users = HM.fromList [ ("pete", PHash (HM.singleton "uid" (PNumber 2000))) , ("tom" , PHash (HM.singleton "uid" (PNumber 2001))) ]++pusers :: HM.HashMap Text PValue pusers = HM.fromList [ ("bob", PHash (HM.singleton "uid" (PNumber 100))) , ("tom" , PHash (HM.singleton "uid" (PNumber 12))) ] +hash :: [(Text, PValue)] -> PValue+hash = PHash . HM.fromList++array :: [PValue] -> PValue+array = PArray . Vector.fromList++spec :: Spec spec = do runIO $ Log.updateGlobalLogger loggerName (Log.setLevel Log.WARNING)- q3 <- runIO $ startHiera "test" config_v3- q5 <- runIO $ startHiera "test" config_v5+ q3_ <- runIO $ startHiera "test" config_v3+ q5_ <- runIO $ startHiera "test" config_v5+ let q5 vrs var t = runExceptT (q5_ vrs var t)+ q3 vrs var t = runExceptT (q3_ vrs var t) describe "Hiera" $ do- describe "v5 lookup hierarchy" $ do- it "should override some values" $ do- q5 vars "http_port" QFirst >>= checkOutput (Just (PNumber 9090))- q5 vars "global" QFirst >>= checkOutput (Just "glob")- describe "v5 ~" $ do- it "should read '~' as a Null/Nothing value" $ do- q5 vars "optional_value" QFirst >>= checkOutput Nothing- describe "v3 lookup with no context variables" $ do- it "should return nothing when called with an empty string" $- q3 mempty "" QFirst >>= checkOutput Nothing- it "should return nothing when called with a non existent key [First merge]" $- q3 mempty "foo" QFirst >>= checkOutput Nothing- it "should return nothing when called with a non existent key [Unique merge]" $- q3 mempty "foo" QUnique >>= checkOutput Nothing- it "should return nothing when called with a non existent key [Hash merge]" $- q3 mempty "foo" QHash >>= checkOutput Nothing- it "should return common data" $- q3 mempty "http_port" QFirst >>= checkOutput (Just (PNumber 8080))- it "should return arrays" $- q3 mempty "ntp_servers" QFirst >>= checkOutput (Just (PArray (Vector.fromList ["0.ntp.puppetlabs.com","1.ntp.puppetlabs.com"])))- it "should return hashes" $- q3 mempty "users" QFirst >>= checkOutput (Just (PHash users))- describe "v3 lookup hierarchy" $ do- it "should override value" $- q3 vars "http_port" QFirst >>= checkOutput (Just (PNumber 9090))- it "should find common value" $- q3 vars "global" QFirst >>= checkOutput (Just "glob")- describe "v3 json backend" $- it "resolves in json" $- q3 vars "testjson" QFirst >>= checkOutput (Just "ok")- describe "v3 deep interpolation" $ do- it "resolves in strings" $- q3 vars "interp1" QFirst >>= checkOutput (Just (PString ("**" <> fqdn <> "**")))- it "resolves in objects" $- q3 vars "testnode" QFirst >>= checkOutput (Just (PHash (HM.fromList [("1",PString ("**" <> fqdn <> "**")),("2",PString "nothing special")])))- it "resolves in arrays" $- q3 vars "arraytest" QFirst >>= checkOutput (Just (PArray (Vector.fromList [PString "a", PString fqdn, PString "c"])))- describe "v3 other merge modes" $ do- it "catenates arrays" $- q3 vars "ntp_servers" QUnique >>= checkOutput (Just (PArray (Vector.fromList ["2.ntp.puppetlabs.com","3.ntp.puppetlabs.com","0.ntp.puppetlabs.com","1.ntp.puppetlabs.com"])))- it "puts single values in arrays" $- q3 vars "http_port" QUnique >>= checkOutput (Just (PArray (Vector.fromList [PNumber 9090, PNumber 8080])))- it "merges hashes" $- q3 vars "users" QHash >>= checkOutput (Just (PHash (pusers <> users)))+ interpolationSpec+ describe "v5 lookup hierarchy" $+ it "should override some values" $ do+ q5 vars "http_port" QFirst >>= checkOutput (Just (PNumber 9090))+ q5 vars "global" QFirst >>= checkOutput (Just "glob")+ describe "v5 ~" $+ it "should read '~' as a Null/Nothing value" $+ q5 vars "optional_value" QFirst >>= checkOutput (Just PUndef)+ describe "v3 lookup with no context variables" $ do+ it "should return nothing when called with an empty string" $+ q3 mempty "" QFirst >>= checkOutput Nothing+ it "should return nothing when called with a non existent key [First merge]" $+ q3 mempty "foo" QFirst >>= checkOutput Nothing+ it "should return nothing when called with a non existent key [Unique merge]" $+ q3 mempty "foo" QUnique >>= checkOutput Nothing+ it "should return nothing when called with a non existent key [Hash merge]" $+ q3 mempty "foo" QHash >>= checkOutput Nothing+ it "should return common data" $+ q3 mempty "http_port" QFirst >>= checkOutput (Just (PNumber 8080))+ it "should return arrays" $+ q3 mempty "ntp_servers" QFirst >>= checkOutput (Just (array ["0.ntp.puppetlabs.com","1.ntp.puppetlabs.com"]))+ it "should return hashes" $+ q3 mempty "users" QFirst >>= checkOutput (Just (PHash users))+ describe "v3 lookup hierarchy" $ do+ it "should override value" $+ q3 vars "http_port" QFirst >>= checkOutput (Just (PNumber 9090))+ it "should find common value" $+ q3 vars "global" QFirst >>= checkOutput (Just "glob")+ describe "v3 json backend" $+ it "resolves in json" $+ q3 vars "testjson" QFirst >>= checkOutput (Just "ok")+ describe "v3 deep interpolation" $ do+ it "resolves in strings" $+ q3 vars "interp1" QFirst >>= checkOutput (Just (PString ("**" <> fqdn <> "**")))+ it "resolves in objects" $+ q3 vars "testnode" QFirst >>= checkOutput (Just (hash [("1",PString ("**" <> fqdn <> "**")),("2",PString "nothing special")]))+ it "resolves in arrays" $+ q3 vars "arraytest" QFirst >>= checkOutput (Just (array [PString "a", PString fqdn, PString "c"]))+ it "resolves aliases" $+ q3 vars "aliased" QFirst >>= checkOutput (Just (array [PString "a", PString "b"]))+ it "resolves integers to strings" $+ q3 vars "server" QFirst >>= checkOutput (Just (PString "127.0.0.1:9090"))+ it "resolves lookus" $+ q3 vars "aliased_lookup" QFirst >>= checkOutput (Just (PNumber 100))+ describe "v3 other merge modes" $ do+ it "catenates arrays" $+ q3 vars "ntp_servers" QUnique >>= checkOutput (Just (array ["2.ntp.puppetlabs.com","3.ntp.puppetlabs.com","0.ntp.puppetlabs.com","1.ntp.puppetlabs.com"]))+ it "puts single values in arrays" $+ q3 vars "http_port" QUnique >>= checkOutput (Just (array [PNumber 9090, PNumber 8080]))+ it "merges hashes" $+ q3 vars "users" QHash >>= checkOutput (Just (PHash (pusers <> users)))++interpolationSpec :: Spec+interpolationSpec =+ describe "interpolation" $ do+ q_ <- runIO $ startHiera "test" configInterpolate+ let q vrs var t = runExceptT (q_ vrs var t)+ describe "when doing interpolation" $ do+ it "should prevent endless recursion" $+ q mempty "foo" QFirst >>= checkFail+ it "produces a nested hash with arrays from nested aliases with hashes and arrays" $+ q mempty "root" QHash >>= checkOutput (Just (hash [("a", hash [("aa", hash [("b", hash [("bb", PArray (Vector.fromList ["text"]))])])])]))+ it "allows keys with white space" $+ q mempty "ws_key" QFirst >>= checkOutput (Just "value for a ws key")+ it "allows keys with non alphanumeric characters" $+ q mempty "angry" QFirst >>= checkOutput (Just "not happy")++ describe "when not finding value for interpolated key" $+ it "should resolve the interpolation to an empty string" $+ q mempty "niltest" QFirst >>= checkFail -- puppet behavior: checkOutput (Just "Missing key ##. Key with nil ##")++ describe "when there are empty interpolations %{} in data" $ do+ it "should should produce an empty string for the interpolation" $ do+ pendingWith "Support empty interpolation"+ q mempty "empty_interpolation" QFirst >>= checkOutput (Just "clownshoe")+ it "the empty interpolation can be escaped" $ do+ pendingWith "Support empty interpolation"+ q mempty "escaped_empty_interpolation" QFirst >>= checkOutput (Just "clown%{shoe}s")+ it "the value can consist of only an empty escape" $ do+ pendingWith "Support empty interpolation"+ q mempty "only_empty_interpolation" QFirst >>= checkOutput (Just "")+ it "the value can consist of an empty namespace %{::}" $ do+ pendingWith "Support empty interpolation"+ q mempty "empty_namespace" QFirst >>= checkOutput (Just "")+ it "the value can consist of whitespace %{ :: }" $ do+ pendingWith "Support empty interpolation"+ q mempty "whitespace1" QFirst >>= checkOutput (Just "")+ it "the value can consist of whitespace %{ }" $ do+ pendingWith "Support empty interpolation"+ q mempty "whitespace2" QFirst >>= checkOutput (Just "")++ describe "when there are quoted empty interpolations %{} in data" $ do+ it "should should produce an empty string for the interpolation" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_empty_interpolation" QFirst >>= checkOutput (Just "clownshoe")+ it "the empty interpolation can be escaped" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_escaped_empty_interpolation" QFirst >>= checkOutput (Just "clown%{shoe}s")+ it "the value can consist of only an empty escape" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_only_empty_interpolation" QFirst >>= checkOutput (Just "")+ it "the value can consist of an empty namespace %{::}" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_empty_namespace" QFirst >>= checkOutput (Just "")+ it "the value can consist of whitespace %{ :: }" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_whitespace1" QFirst >>= checkOutput (Just "")+ it "the value can consist of whitespace %{ }" $ do+ pendingWith "Support empty interpolation"+ q mempty "quoted_whitespace2" QFirst >>= checkOutput (Just "")++ describe "varsplitter" $ do+ it "no splitting" $ varSplitter "abcd" `shouldBe` ["abcd"]+ it "split 2" $ varSplitter "ab.cd" `shouldBe` ["ab", "cd"]+ it "split 3" $ varSplitter "ab.cd.ef" `shouldBe` ["ab", "cd", "ef"]+ it "split dq" $ varSplitter "\"ab\"" `shouldBe` ["ab"]+ it "split dq 2" $ varSplitter "\"ab.cd\"" `shouldBe` ["ab.cd"]+ it "split dq 2 mixed" $ varSplitter "\"ab.cd\".ef" `shouldBe` ["ab.cd", "ef"]+ it "split dq 2 mixed 4" $ varSplitter "\"ab.cd\".ef.\"lol.cat\".bar" `shouldBe` ["ab.cd", "ef", "lol.cat", "bar"]+ it "split sq" $ varSplitter "'ab'" `shouldBe` ["ab"]+ it "split sq 2" $ varSplitter "'ab.cd'" `shouldBe` ["ab.cd"]+ it "split sq 2 mixed" $ varSplitter "'ab.cd'.ef" `shouldBe` ["ab.cd", "ef"]+ it "split sq 2 mixed 4" $ varSplitter "'ab.cd'.ef.'lol.cat'.bar" `shouldBe` ["ab.cd", "ef", "lol.cat", "bar"]+ it "split all mixed" $ varSplitter "'a.b'.\"c.d\".e.f" `shouldBe` ["a.b", "c.d", "e", "f"]++ describe "when using dotted keys" $ do+ it "should find an entry using a quoted interpolation" $+ q (HM.fromList [("a.b", "(scope) a dot b")]) "\"a.c.scope\"" QFirst >>= checkOutput (Just "a dot c: (scope) a dot b")+ it "should find an entry using a quoted interpolation with method hiera" $+ q (HM.fromList [("a.b", "(scope) a dot b")]) "\"a.c.hiera\"" QFirst >>= checkOutput (Just "a dot c: (hiera) a dot b")+ it "should find an entry using a quoted interpolation with method alias" $+ q (HM.fromList [("a.b", "(scope) a dot b")]) "\"a.c.alias\"" QFirst >>= checkOutput (Just "(hiera) a dot b")+ it "should use a dotted key to navigate into a structure when it is not quoted" $+ q (HM.fromList [("a", hash [("d", "(scope) a dot d is a hash entry")])]) "\"a.e.scope\"" QFirst >>= checkOutput (Just "a dot e: (scope) a dot d is a hash entry")+ it "should use a dotted key to navigate into a structure when when it is not quoted with method hiera" $+ q (HM.fromList [("a", hash [("d", "(scope) a dot d is a hash entry")])]) "\"a.e.hiera\"" QFirst >>= checkOutput (Just "a dot e: (hiera) a dot d is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is last" $+ q (HM.fromList [("a", hash [("d.x", "(scope) a dot d.x is a hash entry")])]) "\"a.ex.scope\"" QFirst >>= checkOutput (Just "a dot ex: (scope) a dot d.x is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is last and method is hiera" $+ q (HM.fromList [("a", hash [("d.x", "(scope) a dot d.x is a hash entry")])]) "\"a.ex.hiera\"" QFirst >>= checkOutput (Just "a dot ex: (hiera) a dot d.x is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is first" $+ q (HM.fromList [("a.x", hash [("d", "(scope) a.x dot d is a hash entry")])]) "\"a.xe.scope\"" QFirst >>= checkOutput (Just "a dot xe: (scope) a.x dot d is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is first and method is hiera" $+ q (HM.fromList [("a.x", hash [("d", "(scope) a.x dot d is a hash entry")])]) "\"a.xe.hiera\"" QFirst >>= checkOutput (Just "a dot xe: (hiera) a.x dot d is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle" $+ q (HM.fromList [("a", hash [("d.z", hash [("g", "(scope) a dot d.z dot g is a hash entry")])])]) "\"a.xm.scope\"" QFirst >>= checkOutput (Just "a dot xm: (scope) a dot d.z dot g is a hash entry")+ it "should use a mix of quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle and method is hiera" $+ q (HM.fromList [("a", hash [("d.z", hash [("g", "(scope) a dot d.z dot g is a hash entry")])])]) "\"a.xm.hiera\"" QFirst >>= checkOutput (Just "a dot xm: (hiera) a dot d.z dot g is a hash entry")+ it "should use a mix of several quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle" $+ q (HM.fromList [("a.x", hash [("d.z", hash [("g", "(scope) a.x dot d.z dot g is a hash entry")])])]) "\"a.xx.scope\"" QFirst >>= checkOutput (Just "a dot xx: (scope) a.x dot d.z dot g is a hash entry")+ it "should use a mix of several quoted and dotted keys to navigate into a structure containing dotted keys and quoted key is in the middle and method is hiera" $+ q (HM.fromList [("a.x", hash [("d.z", hash [("g", "(scope) a.x dot d.z dot g is a hash entry")])])]) "\"a.xx.hiera\"" QFirst >>= checkOutput (Just "a dot xx: (hiera) a.x dot d.z dot g is a hash entry")+ it "should find an entry using using a quoted interpolation on dotted key containing numbers" $+ q (HM.fromList [("x.1", "(scope) x dot 1")]) "\"x.2.scope\"" QFirst >>= checkOutput (Just "x dot 2: (scope) x dot 1")+ it "should find an entry using using a quoted interpolation on dotted key containing numbers using method hiera" $+ q (HM.fromList [("x.1", "(scope) x dot 1")]) "\"x.2.hiera\"" QFirst >>= checkOutput (Just "x dot 2: (hiera) x dot 1")+ it "will allow strange characters in the key" $+ q mempty "very_angry" QFirst >>= checkOutput (Just "not happy at all")+ it "should not find a subkey when the dotted key is quoted" $+ q (HM.fromList [("a", hash [("f", "(scope) a dot f is a hash entry")])]) "\"a.f.scope\"" QFirst >>= checkFail -- real hiera : checkOutput (Just "a dot f: ")+ it "should not find a subkey when the dotted key is quoted with method hiera" $+ q (HM.fromList [("a", hash [("f", "(scope) a dot f is a hash entry")])]) "\"a.f.hiera\"" QFirst >>= checkFail -- real hiera : checkOutput (Just "a dot f: ")+ it "should not find a subkey that is matched within a string" $+ q mempty "ipl_key" QFirst >>= checkFail+ it "should not find a subkey that is matched within a string" $+ q mempty "key.subkey" QFirst >>= checkFail+
tests/Interpreter/Function/LookupSpec.hs view
@@ -5,11 +5,15 @@ main :: IO () main = hspec spec +fname :: Text fname = "lookup"+expectedErrMsg :: String expectedErrMsg = "Wrong set of arguments" -- See dummyFacts defined in Pure.hs+testkey :: Expression testkey = "foo"+expectedValue :: Text expectedValue = "dummy" checkSuccess :: [Expression] -> Text -> Expectation@@ -18,6 +22,7 @@ checkError :: [Expression] -> String -> Expectation checkError = checkExprsError fname +boolDatatype, stringDatatype :: Expression boolDatatype = Terminal (UDataType UDTBoolean) stringDatatype = Terminal (UDataType (UDTString Nothing Nothing))
+ tests/hiera/interpolate/config/hiera.yaml view
@@ -0,0 +1,14 @@+:backends:+ - yaml++:hierarchy:+ - recursive+ - niltest+ - complex+ - empty_%{}inter%{::}polation+ - dotted_keys+ - weird_keys+ - bad_interpolation++:yaml:+ :datadir: '../data'
+ tests/hiera/interpolate/config/hiera_iplm_hiera.yaml view
@@ -0,0 +1,6 @@+:backends:+ - json++:hierarchy:+ - role+ - "%{hiera('role')}"
+ tests/hiera/interpolate/config/hiera_iplm_hiera_bad.yaml view
@@ -0,0 +1,5 @@+:backends:+ - yaml++:hierarchy:+ - "%{hiera('role')}"
+ tests/hiera/interpolate/data/bad_interpolation.yaml view
@@ -0,0 +1,9 @@+---+quote_mismatch: 'Key delimited with singe quote on one side aand double qoute on the other: %{''the.key"}'+quote_mismatch_arg: 'Arg delimited with singe quote on one side and double qoute on the other: %{hiera(''the.key")}'+non_existing_method: 'The method flubber does not exist: %{flubber("hello")}'++one_quote: 'Key with only one quote: %{the.''key}'+empty_segment: 'Key with only one quote: %{the..key}'+empty_quoted_segment: 'Key with only one quote: %{the.''''.key}'+partly_quoted_segment: 'Key with only one quote: %{the.''pa''key}'
+ tests/hiera/interpolate/data/complex.yaml view
@@ -0,0 +1,12 @@+---+root:+ a:+ aa: "%{alias('aaa')}"++aaa:+ b:+ bb: "%{alias('bbb')}"++bbb: [ "%{alias('ccc')}" ]++ccc: text
+ tests/hiera/interpolate/data/dotted_keys.yaml view
@@ -0,0 +1,43 @@+---+a.b: '(hiera) a dot b'+a.c.scope: "a dot c: %{'a.b'}"+a.c.hiera: 'a dot c: %{hiera("''a.b''")}'+a.c.scope: "a dot c: %{'a.b'}"+a.c.hiera: 'a dot c: %{hiera("''a.b''")}'+a.c.alias: '%{alias("''a.b''")}'+a:+ d: '(hiera) a dot d is a hash entry'+ d.x: '(hiera) a dot d.x is a hash entry'+ d.z:+ g: '(hiera) a dot d.z dot g is a hash entry'++a.x:+ d: '(hiera) a.x dot d is a hash entry'+ d.x: '(hiera) a.x dot d.x is a hash entry'+ d.z:+ g: '(hiera) a.x dot d.z dot g is a hash entry'++a.e.scope: "a dot e: %{a.d}"+a.e.hiera: "a dot e: %{hiera('a.d')}"++a.ex.scope: "a dot ex: %{a.'d.x'}"+a.ex.hiera: 'a dot ex: %{hiera("a.''d.x''")}'++a.xe.scope: "a dot xe: %{'a.x'.d}"+a.xe.hiera: 'a dot xe: %{hiera("''a.x''.d")}'++a.xm.scope: "a dot xm: %{a.'d.z'.g}"+a.xm.hiera: 'a dot xm: %{hiera("a.''d.z''.g")}'++a.xx.scope: "a dot xx: %{'a.x'.'d.z'.g}"+a.xx.hiera: 'a dot xx: %{hiera("''a.x''.''d.z''.g")}'++a.f.scope: "a dot f: %{'a.d'}"+a.f.hiera: 'a dot f: %{hiera("''a.d''")}'++x.1: '(hiera) x dot 1'+x.2.scope: "x dot 2: %{'x.1'}"+x.2.hiera: 'x dot 2: %{hiera("''x.1''")}'++key: subkey+ipl_key: '- %{hiera("key.subkey")} -'
+ tests/hiera/interpolate/data/empty_interpolation.yaml view
@@ -0,0 +1,13 @@+empty_interpolation: 'clown%{}shoe'+escaped_empty_interpolation: 'clown%%{}{shoe}s'+only_empty_interpolation: '%{}'+empty_namespace: '%{::}'+whitespace1: '%{ :: }'+whitespace2: '%{ }'++quoted_empty_interpolation: 'clown%{""}shoe'+quoted_escaped_empty_interpolation: 'clown%%{""}{shoe}s'+quoted_only_empty_interpolation: '%{""}'+quoted_empty_namespace: '%{"::"}'+quoted_whitespace1: '%{ "::" }'+quoted_whitespace2: '%{ "" }'
+ tests/hiera/interpolate/data/niltest.yaml view
@@ -0,0 +1,2 @@+niltest: 'Missing key #%{hiera("knotfound")}#. Key with nil #%{hiera("knil")}#'+knil: null
+ tests/hiera/interpolate/data/recursive.yaml view
@@ -0,0 +1,3 @@+foo: '%{hiera("bar")}'++bar: '%{hiera("foo")}'
+ tests/hiera/interpolate/data/weird_keys.yaml view
@@ -0,0 +1,12 @@+---++'a key with whitespace': 'value for a ws key'+ws_key: '%{alias("a key with whitespace")}'++'#@!&%|§': 'not happy'+angry: '%{alias("#@!&%|§")}'++'!$\%!':+ '#@!&%|§': 'not happy at all'++very_angry: '%{alias("!$\%!.#@!&%|§")}'
tests/hiera/production.yaml view
@@ -7,3 +7,9 @@ uid: 100 tom: uid: 12+original:+ - a+ - b+aliased: "%{alias('original')}"+server: "127.0.0.1:%{lookup('http_port')}"+aliased_lookup: "%{alias('users.bob.uid')}"