All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pallet.configure.clj Maven / Gradle / Ivy

(ns pallet.configure
  "Pallet configuration using ~/.pallet/config.clj, the pallet.config namespace
   or from settings.xml.

   config.clj should be in ~/.pallet or a directory specified by the PALLET_HOME
   environment variable.

   service definitions can also be specified as clojure maps in
   ~/.pallet/services/*.clj"
  (:require
   [pallet.blobstore :as blobstore]
   [pallet.common.deprecate :as deprecate]
   [pallet.compute :as compute]
   [pallet.environment :as environment]
   [pallet.utils :as utils]
   [clojure.java.io :as java-io]
   [clojure.string :as string]
   [clojure.tools.logging :as logging]
   [clojure.walk :as walk])
  (:use
   [clojure.core.incubator :only [-?>]]))

(def ^{:private true
       :doc "A var to be set by defpallet, so that it may be loaded from any
             namespace"}
  config nil)

(defn- unquote-vals [args]
  (walk/walk
   (fn [item]
     (cond (and (seq? item) (= `unquote (first item))) (second item)
           ;; needed if we want fn literals to be usable by eval-in-project
           (and (seq? item) (= 'fn (first item))) (list 'quote item)
           (symbol? item) (list 'quote item)
           :else (unquote-vals item)))
   identity
   args))

(defmacro defpallet
  "Top level macro for the pallet config.clj file."
  [& {:keys [provider identity credential providers admin-user]
      :as config-options}]
  `(let [m# (zipmap
             ~(cons 'list (keys config-options))
             ~(cons 'list (unquote-vals (vals config-options))))]
    (alter-var-root #'config (fn [_#] m#))))

(defn- read-config
  [file]
  (try
    (use '[pallet.configure :only [defpallet]])
    (load-file file)
    config
    (catch java.io.FileNotFoundException _)))

(defn- home-dir
  "Returns full path to Pallet home dir ($PALLET_HOME or $HOME/.pallet)"
  []
  (.getAbsolutePath
   (doto (if-let [pallet-home (System/getenv "PALLET_HOME")]
           (java.io.File. pallet-home)
           (java.io.File. (System/getProperty "user.home") ".pallet"))
     .mkdirs)))

(defn pallet-config
  "Read pallet configuration from config.clj and services/*.clj files. The
   files are taken from ~/.pallet or $PALLET_HOME if set."
  []
  (reduce
   (fn [config service]
     (assoc-in config [:services (key (first service))] (val (first service))))
   (read-config (.getAbsolutePath (java-io/file (home-dir) "config.clj")))
   (for [file (filter
               #(and (.isFile %) (.endsWith (.getName %) ".clj"))
               (file-seq (java-io/file (home-dir) "services")))]
     (read-string (slurp file)))))

(defn- check-deprecations
  "Provide deprecation warnings."
  [config]
  (when (:providers config)
    (deprecate/warn
     (str
      "Use of :providers key in ~/.pallet/config.clj is "
      "deprecated. Please change to use :services."))))

(defn- cake-project-environment
  "Read an environment from the cake-project if it exists"
  []
  (-?> 'cake/*project* resolve var-get :environment))

;;; Compute service

(defn compute-service-properties
  "Helper to read compute service properties. Given a config file return the
   selected service definition as a map."
  [config profiles]
  (when config
    (let [service (first profiles)
          default-service (map config [:provider :identity :credential])
          services (:services config (:providers config))
          environment (when-let [env (:environment config)]
                        (environment/eval-environment env))]
      (cond
       ;; no specific service requested, and default service specified by
       ;; top level keys in defppallet
       (and
        (not service)
        (every? identity default-service)) (->
                                            (select-keys
                                             config
                                             [:provider :identity :credential
                                              :blobstore :endpoint
                                              :environment])
                                            (utils/maybe-update-in
                                             [:environment]
                                             (fn [env] environment)))
        ;; pick from specified services
       (map? services) (->
                        (or
                         (and service
                              ;; ensure that if services is specified as a
                              ;; vector of keyword value vectors, that
                              ;; it is converted into a map first.
                              (let [services (into {} services)]
                                (or
                                 (services (keyword service))
                                 (services service))))
                         (and (not service) ; use default if service unspecified
                              (when-let [service (first services)]
                                (-> service second))))
                        ;; merge any top level environment with the service
                        ;; specific environment
                        (utils/maybe-update-in
                         [:environment]
                         #(environment/merge-environments
                           environment
                           (environment/eval-environment
                            (cake-project-environment))
                           (environment/eval-environment %))))
       :else nil))))

(defn compute-service-from-map
  "Create a compute service from a credentials map.
   Uses the :provider, :identity, :credential, :extensions and :node-list keys.
   The :extensions and :node-list keys will be read with read-string if they
   are strings."
  [credentials]
  (let [options (->
                 credentials
                 (update-in [:extensions]
                            #(if (string? %)
                               (map read-string (string/split % #" "))
                               %))
                 (update-in [:node-list] #(if (string? %) (read-string %) %))
                 (update-in [:environment] #(environment/eval-environment %)))]
    (when-let [provider (:provider options)]
      (apply
       compute/compute-service
       provider
       (apply concat (filter second (dissoc options :provider)))))))

(defn compute-service-from-config
  "Compute service from a defpallet configuration map and a list of active
   profiles (provider keys)."
  [config profiles]
  (check-deprecations config)
  (compute-service-from-map
   (compute-service-properties config profiles)))

(defn compute-service-from-settings
  "Create a compute service from maven property settings.
   In Maven's settings.xml you can define a profile, that contains
   pallet.compute.provider, pallet.compute.identity and
   pallet.compute.credential values."
  [& profiles]
  (try
    (require 'pallet.maven)             ; allow running without maven jars
    (when-let [f (ns-resolve 'pallet.maven 'credentials)]
      (when-let [service (compute-service-from-map (f profiles))]
        (deprecate/warn
         (str
          "Use of settings.xml for pallet configuration is "
          "deprecated. Please change to use config.clj."))
        service))
    (catch ClassNotFoundException _)
    (catch clojure.lang.Compiler$CompilerException _)))

(defn compute-service-from-config-var
  "Checks to see if pallet.config/service is a var, and if so returns its
  value."
  []
  (utils/find-var-with-require 'pallet.config 'service))

(defn compute-service-from-property
  "If the pallet.config.service property is defined, and refers to a var, then
   return its value."
  []
  (when-let [property (System/getProperty "pallet.config.service")]
    (when-let [sym-names (and (re-find #"/" property)
                              (string/split property #"/"))]
      (utils/find-var-with-require
       (symbol (first sym-names)) (symbol (second sym-names))))))

(defn compute-service-from-config-file
  "Compute service from ~/.pallet/config.clj. Profiles is a sequence of service
   keys to use from the :services map."
  [& profiles]
  (compute-service-from-config (pallet-config) profiles))

(defn compute-service
  "Instantiate a compute service.

   If passed no arguments, then the compute service is looked up in the
   following order:
   - from a var referenced by the pallet.config.service system property
   - from pallet.config/service if defined
   - the first service in config.clj
   - the service from the first active profile in settings.xml

   If passed a service name, it is looked up in external
   configuration (~/.pallet/config.clj or ~/.m2/settings.xml). A service name is
   one of the keys in the :services map in config.clj, or a profile id in
   settings.xml.

   When passed a provider name and credentials, the service is instantiated
   based on the credentials.  The provider name should be a recognised provider
   name (see `pallet.compute/supported-providers` to obtain a list of these).

   The other arguments are keyword value pairs.
   - :identity     username or key
   - :credential   password or secret
   - :extensions   extension modules for jclouds
   - :node-list    a list of nodes for the \"node-list\" provider.
   - :environment  an environment map with service specific values."
  ([]
     (or
      (compute-service-from-property)
      (compute-service-from-config-var)
      (compute-service-from-config-file)
      (compute-service-from-settings)))
  ([service-name]
     (or
      (compute-service-from-config-file service-name)
      (compute-service-from-settings service-name)))
  ([provider-name
    & {:keys [identity credential extensions node-list endpoint environment]
       :as options}]
     (apply compute/compute-service provider-name (apply concat options))))

;;; Blobstore

(def ^{:doc "Translate compute provider to associated blobstore provider"}
  blobstore-lookup
  {"cloudservers" "cloudfiles"
   "cloudservers-us" "cloudfiles-us"
   "cloudservers-eu" "cloudfiles-eu"
   "ec2" "s3"
   "aws-ec2" "aws-s3"})

(defn blobstore-from-map
  "Create a blobstore service from a credentials map.
   Uses :provider, :identity, :credential and
   :blobstore-provider, :blobstore-identity and :blobstore-credential.
   Blobstore keys fall back to the compute keys"
  [credentials]
  (when-let [provider (or (:blobstore-provider credentials)
                          (blobstore-lookup (:provider credentials)))]
    (blobstore/service
     provider
     :identity (or (:blobstore-identity credentials)
                   (:identity credentials))
     :credential (or (:blobstore-credential credentials)
                     (:credential credentials)))))

(defn blobstore-from-settings
  "Create a blobstore service from ~/.m2/settings.xml propery settings."
  [& profiles]
  (try
    (require 'pallet.maven)             ; allow running without maven jars
    (when-let [f (ns-resolve 'pallet.maven 'credentials)]
      (when-let [service (blobstore-from-map (f profiles))]
        (deprecate/warn
         (str
          "Use of settings.xml for pallet configuration is "
          "deprecated. Please change to use config.clj."))
        service))
    (catch ClassNotFoundException _)
    (catch clojure.lang.Compiler$CompilerException _)))

(defn blobstore-from-config
  "Create a blobstore service form a configuration map."
  [config profiles]
  (let [config (compute-service-properties config profiles)
        {:keys [provider identity credential]} (merge
                                                (update-in
                                                 config [:provider]
                                                 (fn [p]
                                                   (blobstore-lookup p)))
                                                (:blobstore config))]
    (when provider
      (blobstore/service provider :identity identity :credential credential))))

(defn blobstore-service-from-config-var
  "Checks to see if pallet.config/service is a var, and if so returns its
  value."
  []
  (utils/find-var-with-require 'pallet.config 'blobstore-service))

(defn blobstore-service-from-property
  "If the pallet.config.service property is defined, and refers to a var, then
   return its value."
  []
  (when-let [property (System/getProperty "pallet.config.blobstore-service")]
    (when-let [sym-names (and (re-find #"/" property)
                              (string/split property #"/"))]
      (utils/find-var-with-require
       (symbol (first sym-names)) (symbol (second sym-names))))))

(defn blobstore-service-from-config-file
  "Create a blobstore service form a configuration map."
  [& profiles]
  (blobstore-from-config (pallet-config) profiles))

(defn blobstore-service
  "Instantiate a blobstore service.

   If passed no arguments, then the blobstore service is looked up in the
   following order:
   - from a var referenced by pallet.config.blobstore-service system property
   - from pallet.config/blobstore-service if defined
   - the first service in config.clj
   - the service from the first active profile in settings.xml

   If passed a service name, it is looked up in external
   configuration (~/.pallet/config.clj or ~/.m2/settings.xml). A service name is
   one of the keys in the :services map in config.clj, or a profile id in
   settings.xml.

   When passed a provider name and credentials, the service is instantiated
   based on the credentials.  The provider name should be a recognised provider
   name (see `pallet.blobstore/supported-providers` to obtain a list of these).

   The other arguments are keyword value pairs.
   - :identity     username or key
   - :credential   password or secret
   - :extensions   extension modules for jclouds
   - :node-list    a list of nodes for the \"node-list\" provider.
   - :environment  an environment map with service specific values."
  ([]
     (or
      (blobstore-service-from-property)
      (blobstore-service-from-config-var)
      (blobstore-service-from-config-file)))
  ([service-name]
     (or
      (blobstore-service-from-config-file service-name)))
  ([provider-name
    & {:keys [identity credential extensions node-list endpoint environment]
       :as options}]
     (apply blobstore/service provider-name (apply concat options))))

;;; Admin user

(defn admin-user-from-property
  "If the pallet.config.admin-user property is defined, and refers to a var
   then return its value."
  []
  (when-let [property (System/getProperty "pallet.config.admin-user")]
    (when-let [sym-names (and (re-find #"/" property)
                              (string/split property #"/"))]
      (utils/find-var-with-require
       (symbol (first sym-names)) (symbol (second sym-names))))))

(defn admin-user-from-config-var
  "Set the admin user based on pallet.config setup."
  []
  (utils/find-var-with-require 'pallet.config 'admin-user))

(defn admin-user-from-config
  "Set the admin user based on a config map"
  [config]
  (when-let [admin-user (:admin-user config)]
    (apply utils/make-user (:username admin-user) (apply concat admin-user))))

(defn admin-user-from-config-file
  "Create an admin user form a configuration map."
  []
  (admin-user-from-config (pallet-config)))

(defn admin-user
  "Instantiate an admin-user.

   If passed no arguments, then the blobstore service is looked up in the
   following order:
   - from a var referenced by pallet.config.admin-user system property
   - from pallet.config/admin-user if defined
   - the :admin-user top level key in config.clj

   Service specific admin-user values should be specified through a :user
   key on the :environment for the service.

   The other arguments are keyword value pairs.
   - :identity     username or key
   - :credential   password or secret
   - :extensions   extension modules for jclouds
   - :node-list    a list of nodes for the \"node-list\" provider.
   - :environment  an environment map with service specific values."
  ([]
     (or
      (admin-user-from-property)
      (admin-user-from-config-var)
      (admin-user-from-config-file))))

;;; Service map

(defn service-map
  "Instantiate service objects. The service objects are returned in a map
   with keys as expected by `configure` or `lift`."
  ([]
     {:compute (compute-service)
      :blobstore (blobstore-service)
      :user (admin-user)})
  ([service-name]
     {:compute (compute-service service-name)
      :blobstore (blobstore-service service-name)
      :user (admin-user)}))




© 2015 - 2025 Weber Informatics LLC | Privacy Policy