hal-platform / hal

:shipit: Hal Deployment Platform - Web UI/API
MIT License
18 stars 4 forks source link

Add symfony config extension for handling config #17

Closed skluck closed 7 years ago

skluck commented 7 years ago

hal-core, hal-agent and hal-ui should all have config extensions for defining their required config parameters.

nagibyro commented 7 years ago

Sample config changes. config.global.yml and config.yml would be collapsed together.

example:

config.yml

general:
    application.id: '200947'
    application.major.version: 2
    application.sha: ''
    application.title: 'Hal'

    date.timezone: 'America/Detroit'

    unique.alphabet: '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
    unique.size: 4
    date.timezone: 'America/Detroit'

    gravatar.fallback: 'skluck.github.io/hal/halprofile_100.jpg'

cookie:
    session.cookie.configuration:
        lifetime: '5 days'
    cookie.perferences.ttl: '5 years'

github:
    permissions.check.github: true

slim:
    slim.configuration:
      debug: false

twig:
    debug: false

crypto:
    encrypter.hal.secret.path: 'configuration/hal.encrypter.secret'

dev.yml

imports:
    - { resource: 'config.yml' }

general:
    application.title: 'Hal Dev'

doctrine:
    devmode: true

    connection:
        driver: pdo_mysql
        host: '127.0.0.1'
        user: 'hal'
        password: ''
        dbname: 'hal'

cache:
    api.cachetimes:
        # these are lower because having the most update to date status is critical
        api.build: 5
        api.push: 5
        api.queue: 0 # the queue api uses no caching
        api.queue.refresh: 0 # the queue api uses no caching

    # 30 min for permissions
    permissions.ttl: 1800
    doctrine.ttl: 600
    doctrine.cache.service: 'Doctrine\Common\Cache\ArrayCache'
    cache.service: 'QL\MCP\Cache\MemoryCache'
    server.ttl: 300
    stats.ttl: 900
    page.ttl: 300
    github.default.ttl: 60
    github.short.ttl: 20

github:
    token: ''
    app.id: ''
    secret: ''
    baseurl: ''

redis:
    hosts: ['localhost:6379']
    prefix: 'hal9000dev'

agents:
    hosts: ['localhost']

ldap:
  host: ''
  domain: ''
  base_dn: ''
  port: ''

cookie:
    cookie.secret: 'is it secret?'
    session.secret: 'is it safe?'

crypto:
    encrypter.publickey: |
       PUBLIC KEY

    encrypter.encryptedkey: |
        ENCRYPT KEY

Each top level section would have it's own configuration class that and the HalExtension would run them all. and set the proper values into parameters or services.

GeneralConfiguration

class GeneralConfiguration implements ConfigurationInterface
{

    /**
     * Generates the configuration tree builder.
     *
     * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('general');

        $rootNode
            ->children()
                ->scalarNode('application.id')->end()
                ->scalarNode('application.title')->defaultValue('Hal')->end()
                ->integerNode('application.major.version')->min(0)->defaultValue(0)->end()
                ->enumNode('application.env')->values(['dev', 'test', 'prod'])->end()
            ->end();
    }
}

HalExtension

The extension becomes mostly a large mapping of config values to their previous parameter values.

class HalExtension extends Extension
{

    /**
     * Loads a specific configuration.
     *
     * @param array $configs An array of configuration values
     * @param ContainerBuilder $container A ContainerBuilder instance
     *
     * @throws \InvalidArgumentException When provided tag is not defined in this extension
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader(
            $container,
            new FileLocator(__DIR__ . '/../../../configuration')
        );
        $loader->load('new-config.yml');
        $loader->load('new-config.env.yml');

        // Save database password from encrypted properties on Hal deployment
        if (false !== ($property = getenv('ENCRYPTED_HAL_DB_PASS'))) {
            $container->setParameter('database.password', $property);
        }

        // Save LDAP password from encrypted properties on Hal deployment
        if (false !== ($property = getenv('ENCRYPTED_LDAP_PASS'))) {
            $container->setParameter('ldap.password', $property);
        }

        // Save commit SHA on Hal deployment
        if (false !== ($property = getenv('HAL_COMMIT'))) {
            $container->setParameter('application.sha', $property);
        }
        // This session secret is generated on each deploy, so that:
        // 1. Users are automatically logged out when new HAL code is deployed
        // 2. Users cannot look in code and find a way to decrypt and thus fake session data
        if (false !== ($property = getenv('HAL_ENCRYPTION_SECRET'))) {
            $container->setParameter('session.encryption.secret', $property);
        }

        $this->registerGeneralParameters($configs['general'], $container);
    }

    private function registerGeneralParameters(array $generalConfig, ContainerBuilder $container)
    {
        $container->setParameter('application.title', $generalConfig['application.title']);
        $container->setParameter('application.environment', $generalConfig['application.environment']);
        $container->setParameter('application.id', $generalConfig['application.id']);
        // Save commit SHA on Hal deployment
        if (false !== ($property = getenv('HAL_COMMIT'))) {
            $container->setParameter('application.sha', $property);
        }

        $container->setParameter('date.timezone', $generalConfig['date.timezone']);
        $container->setParameter('unique.alphabet', $generalConfig['unique.alphabet']);
        $container->setParameter('unique.size', $generalConfig['unique.size']);
        $container->setParameter('gravatar.fallback', $generalConfig['gravatar.fallback']);
    }
}
skluck commented 7 years ago

Should defaults be in the config definition instead of a base config?

Also are extensions still run if the container is already compiled? Or only at build time?

nagibyro commented 7 years ago

@skluck Only at build time. Really only when you call $container->loadFromExtension which you can call anytime before you compile.

For the defaults probably put them all in the base config -- I imagine the main use is to avoid having to setup a lot of boilerplate in configs when you are creating a 3rd party bundle. But thats not really an issue for us. Though there could be uses for things like debug modes having default values in the config so that prod.yml and others dont require you to write those in.

nagibyro commented 7 years ago

Hmm so each top level needs to have it's own extension as well as it's own config file. I could just put them all under a hal name so one extension can load all the configuration

hal:
    general:
       ....
    github:
       ....
     redis:
       ....
nagibyro commented 7 years ago

Looking at adding extensions for hal-core and mcp-logger in the UI and Agent

UI

nagibyro commented 7 years ago

Proposed mcp-logger configuration block

mcp_logger:
    syslog_options:
         ident: 'hal' #scalar type
        facility: LOG_USER # string or int -- if string will treat it as php constant value
        silence: true
        options: [LOG_PID, 2] # array of string and ints. strings will be converted to constant values and the array will be bitwise or'd together
    errorlog_options:
        type: 'file' #string or int
        destination: '' #string

    guzzle_options:
        client: [] #array passed through to guzzle client
        uri: 'http://loghere/'

    serializers:
        line_format: '' #string
        json_options: '' #treated same as previous system constants 

    logging_service: 'errorLog' #enum {errorlog|syslog|guzzle|null|custom}
    custom_service_id: 'application.di.key' # used if logging_service set to custom
skluck commented 7 years ago

I like it. The ability to override the service is nice.

Only minor changes:

nagibyro commented 7 years ago

With the latest PR's merged in I'll consider this closed. We probably want to make one for panthor and eventually move the extensions into the mcp and hal-core repositories themselves.