-- | Common data types for PuppetDB. module PuppetDB ( dummyPuppetDB, getDefaultDB, pdbConnect, loadTestDB, generateWireCatalog, puppetDBFacts, module PuppetDB.Core, ) where import Control.Arrow ((***)) import qualified Data.HashMap.Strict as Map import qualified Data.Text as Text import Data.Vector.Lens import Facter import Network.HTTP.Client import Puppet.Language import PuppetDB.Core import PuppetDB.Remote import PuppetDB.TestDB import System.Environment import XPrelude -- | Given a 'PDBType', will try return a sane default implementation. getDefaultDB :: PDBType -> IO (Either PrettyError (PuppetDBAPI IO)) getDefaultDB PDBDummy = return (Right dummyPuppetDB) getDefaultDB PDBRemote = do let url = "http://localhost:8080" mgr <- newManager defaultManagerSettings pdbConnect mgr url getDefaultDB PDBTest = lookupEnv "HOME" >>= \case Just h -> loadTestDB (h <> "/.testdb") Nothing -> fmap Right initTestDB -- | A dummy implementation of 'PuppetDBAPI', that will return empty responses. dummyPuppetDB :: (Monad m) => PuppetDBAPI m dummyPuppetDB = PuppetDBAPI (return "dummy") (const (return ())) (const (return ())) (const (return ())) (const (throwError "not implemented")) (const (return [])) (const (return [])) (throwError "not implemented") (\_ _ -> return []) -- | Turns a 'FinalCatalog' and 'EdgeMap' into a document that can be -- serialized and fed to @puppet apply@. generateWireCatalog :: NodeName -> FinalCatalog -> EdgeMap -> WireCatalog generateWireCatalog node cat edgemap = WireCatalog node "version" edges resources "uiid" where edges = toVectorOf (folded . to (\li -> PuppetEdge (li ^. linksrc) (li ^. linkdst) (li ^. linkType))) (concatOf folded edgemap) resources = toVectorOf folded cat puppetDBFacts :: NodeName -> PuppetDBAPI IO -> IO (HashMap Text PValue) puppetDBFacts node pdbapi = runExceptT (getPDBFacts pdbapi (QEqual FCertname node)) >>= \case Right facts@(_ : _) -> return (Map.fromList (map (\f -> (f ^. factInfoName, f ^. factInfoVal)) facts)) _ -> do rawFacts <- fmap concat (sequence [factNET, factRAM, factOS, fversion, factMountPoints, factOS, factUser, factUName, fenv, factProcessor]) let ofacts = genFacts $ map (Text.pack *** Text.pack) rawFacts (hostname, ddomainname) = Text.break (== '.') node domainname = if Text.null ddomainname then "" else Text.tail ddomainname nfacts = genFacts [ ("fqdn", node), ("hostname", hostname), ("domain", domainname), ("rootrsa", "xxx"), ("operatingsystem", "Ubuntu"), ("puppetversion", "language-puppet"), ("virtual", "xenu"), ("clientcert", node), ("is_virtual", "true"), ("concat_basedir", "/var/lib/puppet/concat") ] allfacts = nfacts `Map.union` ofacts genFacts = Map.fromList return (allfacts & traverse %~ PString & buildOSHash) buildOSHash :: Facts -> Facts buildOSHash facts = case buildObject topLevel of Nothing -> facts Just os -> facts & at "os" ?~ os where buildObject keys = let nobject = foldl' addKey mempty keys in if nobject == mempty then Nothing else Just (PHash nobject) g k = facts ^? ix k topLevel = [ ("name", g "operatingsystem"), ("family", g "osfamily"), ("release", buildObject [("major", g "lsbdistrelease"), ("full", g "lsbdistrelease")]), ( "lsb", buildObject [ ("distcodename", g "lsbdistcodename"), ("distid", g "lsbdistid"), ("distdescription", g "lsbdistdescription"), ("distrelease", g "lsbdistrelease"), ("majdistrelease", g "lsbmajdistrelease") ] ) ] addKey hash (k, mv) = case mv of Nothing -> hash Just v -> hash & at k ?~ v