Git Product home page Git Product logo

puppet-ds_389's Introduction

389 Directory Server module for Puppet

Build Status

Table of Contents

  1. Description
  2. Setup - The basics of getting started with ds_389
  3. Usage - Configuration options and additional functionality
  4. Reference - An under-the-hood peek at what the module is doing and how
  5. Limitations - OS compatibility, etc.
  6. Development - Guide for contributing to the module

Description

This module allows you to install and manage 389 Directory Server, create and bootstrap 389 DS instances, configure SSL, replication, schema extensions and even load LDIF data.

SSL is enabled by default. If you already have an SSL cert you can provide the cert, key, and CA bundle, and they'll be imported into your instance. Otherwise, it'll generate self-signed certificates. Replication is supported for consumers, hubs, and suppliers (both master and multi-master), and there's a Puppet task to reinitialize replication.

Setup

What ds_389 affects

  • Ensures the 389-ds-base and NSS tools packages are installed
  • Increases file descriptors for 389 DS to 8192
  • Ensures a user and group for the daemon
  • Ensures a service for any 389 DS instances created

Beginning with ds_389

Examples

Basic example
include ::ds_389

At a bare minimum, the module ensures that the 389 DS base package and NSS tools are installed, and increases the file descriptors for 389 DS.

You'll probably also want to create a 389 DS instance, though, which you can do by declaring a ds_389::instance resource:

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
}

Usage

Instances

The primary resource for configuring 389 DS is the ds_389::instance define.

In our previous example, we created an instance with the server ID set to the hostname of the node. For a node with a hostname of foo, this would create an instance at /etc/dirsrv/slapd-foo that listens on the default ports of 389 and 636 (for SSL).

SSL

If you have existing SSL certificates you'd like to use, you'd pass them in to the instance with the ssl parameter. It expects a hash with paths (either local file paths on the node or a puppet:/// path) for the PEM files for your certificate, key, and CA bundle. It also requires the certificate nickname for the cert and every CA in the bundle. (pk12util sets the nickname for the certificate to the friendly name of the cert in the pkcs12 bundle, and the nickname for each ca cert to "${the common name(cn) of the ca cert subject} - ${the organization(o) of the cert issuer}".)

To require StartTLS for non-SSL connections, you can pass in the minssf param to specify the minimum required encryption.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
  minssf       => 128,
  ssl          => {
    'cert_path'      => 'puppet:///path/to/ssl_cert.pem',
    'key_path'       => 'puppet:///path/to/ssl_key.pem',
    'ca_bundle_path' => 'puppet:///path/to/ssl_ca.pem',
    'ca_cert_names'  => [
      'Certificate nickname for the first CA cert goes here',
      'Certificate nickname for another CA cert goes here',
    ],
    'cert_name'      => 'Certificate nickname goes here',
  },
}

Replication

If you need to set up replication, you'd pass in the replication config via the replication parameter. At a minimum, it expects a hash with the replication bind dn, replication bind dn password, and replication role (either 'consumer', 'hub', or 'supplier').

Consumer

For a consumer, with our previous example:

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
  replication  => {
    'replication_pass' => 'secret',
    'role'             => 'consumer',
  },
}

This would ensure that the replica bind dn and credentials are present in the instance.

Hub

For a hub, you can also pass in any consumers for the hub as an array of server IDs, and the replication agreement will be created and added to the instance.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
  replication  => {
    'replication_pass' => 'secret',
    'role'             => 'hub',
    'consumers'        => [
      'consumer1',
      'consumer2',
    ],
  },
}
Supplier

For a supplier, you can pass in consumers, and also any hubs or other suppliers (if running in multi-master) that should be present in the instance. You'll also need to provide the replica ID for the supplier.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
  replication  => {
    'replication_pass' => 'secret',
    'role'             => 'hub',
    'suppliers'        => [
      'supplier1',
      'supplier2',
    ],
    'hubs'             => [
      'hub1',
      'hub2',
    ],
    'consumers'        => [
      'consumer1',
      'consumer2',
    ],
  },
}
Initializing replication

Once replication has been configured on all of the desired nodes, you can initialize replication for consumers, hubs, and/or other suppliers by passing the appropriate parameters.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  server_id    => $::hostname,
  replication  => {
    'replication_pass' => 'secret',
    'role'             => 'hub',
    'suppliers'        => [
      'supplier1',
      'supplier2',
    ],
    'hubs'             => [
      'hub1',
      'hub2',
    ],
    'consumers'        => [
      'consumer1',
      'consumer2',
    ],
    'init_suppliers'   => true,
    'init_hubs'        => true,
    'init_consumers'   => true,
  },
}

You can also initialize (or reinitialize) replication with the Puppet task.

Schema extensions

If you need to add any schema extensions, you can can pass those in with the schema_extensions parameter. It expects a hash with the desired ldif filename as the key, and a source reference (either via puppet:/// or an absolute path on the node). Note that schema filenames are typically prefixed with a number that indicates the desired schema load order.

ds_389::instance { 'example':
  root_dn           => 'cn=Directory Manager',
  root_dn_pass      => 'supersecret',
  suffix            => 'dc=example,dc=com',
  cert_db_pass      => 'secret',
  schema_extensions => {
    '99example_schema' => 'puppet:///path/to/example_schema.ldif',
  },
}

Modifying existing LDIF data

If you need to modify any of the default ldif data, (typically configs) you can do so via the modify_ldifs parameter. It expects a hash with the desired ldif filename as the key, and a source reference (either via puppet:/// or an absolute path on the node). The ldif file is created and passed to ldapmodify to load it into the instance.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  modify_ldifs => {
    'example_ldif_modify' => 'puppet:///path/to/example_modify.ldif',
  },
}

You can also declare those separately, by calling their define directly, but you'll need to provide the server id of the instance as well as the root dn and password.

ds_389::modify { 'example_ldif_modify':
  server_id    => 'example',
  source       => 'puppet:///path/to/example_modify.ldif',
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
}

Adding new LDIF data

If you need to add any new ldif data, (typically configs) you can do so via the add_ldifs parameter. It expects a hash with the desired ldif filename as the key, and a source reference (either via puppet:/// or an absolute path on the node). These function similarly to the modify_ldifs param, but are passed to ldapadd instead of ldapmodify.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  add_ldifs    => {
    'example_ldif_add' => 'puppet:///path/to/example_add.ldif',
  },
}

You can also declare those separately, by calling their define directly, but you'll need to provide the server id of the instance as well as the root dn and password.

ds_389::add { 'example_ldif_add':
  server_id    => 'example',
  source       => 'puppet:///path/to/example_add.ldif',
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
}

Adding baseline LDIF data

If you need to load baseline ldif data that runs after any other ldif configuration changes, you can pass those in via the base_load_ldifs parameter.

ds_389::instance { 'example':
  root_dn      => 'cn=Directory Manager',
  root_dn_pass => 'supersecret',
  suffix       => 'dc=example,dc=com',
  cert_db_pass => 'secret',
  base_load_ldifs    => {
    'example_ldif_baseline' => 'puppet:///path/to/example_baseline.ldif',
  },
}

Note that while you can declare these via the ds_389::add define, puppet's resource load ordering may potentially result in it attempting to add the ldif before a configuration change that it requires.

Reference

Classes

Public classes

  • ds_389: Main class, manages the installation and configuration of 389-ds-base.

Private classes

  • ds_389::install: Installs 389-ds-base.
  • ds_389::params: Sets parameters according to platform.

Defined types

  • ds_389::instance: The primary defined type. Creates and manages a 389 DS instance.
  • ds_389::add: Adds ldif data via ldapadd to a 389 DS instance.
  • ds_389::modify: Modifies ldif data via ldapmodify for a 389 DS instance.

The following defines are typically called from an instance.

  • ds_389::replication: Sets up replication for a 389 DS instance.
  • ds_389::schema: Adds a schema extension to a 389 DS instance.
  • ds_389::service: Manages the service for a 389 DS instance.
  • ds_389::ssl: Enables SSL for a 389 DS instance.

Tasks

  • ds_389::reinit_consumer: Reinitializes replication on a node.

Parameters

ds_389

  • package_name: Name of the 389 ds package to install. Default: '389-ds-base'
  • package_ensure: 389 ds package state. Default 'installed'
  • user: User account 389 ds should run as. Default: 'dirsrv'
  • group: Group account 389 ds user should belong to. Default: 'dirsrv'
  • cacerts_path: Target directory the 389 ds certs should be exported to. Default: '/etc/openldap/cacerts'
  • home_dir: Home directory for the 389 ds user account. Default: '/usr/share/dirsrv'
  • instances: A hash of ds_389::instance resources. Optional.

ds_389::instance

  • root_dn: The root dn to ensure. Required.
  • root_dn_pass: The root dn password to ensure. Required.
  • cert_db_pass: The certificate db password to ensure. Required.
  • suffix: The LDAP suffix to use. Required.
  • group: The group for the instance. Default: $::ds_389::group
  • user: The user for the instance. Default: $::ds_389::user
  • server_id: The server identifier for the instance. Default: $::hostname
  • server_host: The fqdn for the instance. Default: $::fqdn
  • server_port: The port to use for non-SSL traffic. Default: 389
  • server_ssl_port: The port to use for SSL traffic. Default: 636
  • minssf: The minimum security strength for connections. Default: 0
  • subject_alt_names: An array of subject alt names, if using self-signed certificates. Optional.
  • replication: A replication config hash. See replication.pp. Optional.
  • ssl: An ssl config hash. See ssl.pp. Optional.
  • ssl_version_min: The minimum TLS version the instance should support. Optional.
  • schema_extensions: A hash of schemas to ensure. See schema.pp. Optional.
  • modify_ldifs: A hash of ldif modify files. See modify.pp. Optional. Optional.
  • add_ldifs: A hash of ldif add files. See add.pp. Optional.
  • base_load_ldifs: A hash of ldif add files to load after all other config files have been added. Optional.

ds_389::modify

  • server_id: The 389 ds instance name. Required.
  • content: The file content to use for the ldif file. Required, unless providing the source.
  • source: The source path to use for the ldif file. Required, unless providing the content.
  • root_dn: The bind DN to use when calling ldapmodify. Required.
  • root_dn_pass: The password to use when calling ldapmodify. Required.
  • server_host: The host to use when calling ldapmodify. Default: $::fqdn
  • server_port: The port to use when calling ldapmodify. Default: 389
  • protocol: The protocol to use when calling ldapmodify. Default: 'ldap'
  • starttls: Whether to use StartTLS when calling ldapmodify. Default: false
  • user: The owner of the created ldif file. Default: $::ds_389::user
  • group: The group of the created ldif file. Default: $::ds_389::group

ds_389::add

  • server_id: The 389 ds instance name. Required.
  • content: The file content to use for the ldif file. Required, unless providing the source.
  • source: The source path to use for the ldif file. Required, unless providing the content.
  • root_dn: The bind DN to use when calling ldapadd. Required.
  • root_dn_pass: The password to use when calling ldapadd. Required.
  • server_host: The host to use when calling ldapadd. Default: $::fqdn
  • server_port: The port to use when calling ldapadd. Default: 389
  • protocol: The protocol to use when calling ldapadd. Default: 'ldap'
  • starttls: Whether to use StartTLS when calling ldapadd. Default: false
  • user: The owner of the created ldif file. Default: $::ds_389::user
  • group: The group of the created ldif file. Default: $::ds_389::group

ds_389::replication

  • replication_pass: The bind dn password of the replication user. Required.
  • root_dn: The root dn for configuring replication. Required.
  • root_dn_pass: The root dn password for configuring replication. Required.
  • role: Replication role. Either 'supplier', 'hub', or 'consumer'. Required.
  • suffix: The LDAP suffix to use. Required.
  • replication_user: The name of the replication user. Default: 'Replication Manager'
  • server_host: The host to use when calling ldapmodify. Default: $::fqdn
  • server_port: The port to use when calling ldapmodify. Default: 389
  • protocol: The protocol to use when calling ldapmodify. Default: 'ldap'
  • starttls: Whether to use StartTLS when calling ldapmodify. Default: false
  • replica_port: The port to use for replication. Default: 389
  • replica_transport: The transport type to use for replication. Default: LDAP
  • user: The owner of the created ldif file. Default: $::ds_389::user
  • group: The group of the created ldif file. Default: $::ds_389::group
  • id: The replica id. Optional unless declaring a supplier.
  • purge_delay: Time in seconds state information stored in replica entries is retained. Default: 604800
  • bind_dn: The bind dn of the replication user. Optional.
  • suppliers: An array of supplier names to ensure. Optional.
  • hubs: An array of hub names to ensure. Optional.
  • consumers: An array of consumer names to ensure. Optional.
  • excluded_attributes: An array of attributes to exclude from replication. Optional.
  • init_suppliers: Whether to initialize replication for suppliers. Default: false
  • init_hubs: Whether to initialize replication for hubs. Default: false
  • init_consumers: Whether to initialize replication for consumers. Default: false

ds_389::schema

  • server_id: The 389 ds instance name. Required.
  • source: The source path to use for the ldif file. Required.
  • user: The owner of the created ldif file. Default: $::ds_389::user
  • group: The group of the created ldif file. Default: $::ds_389::group

ds_389::service

  • service_ensure: The state the service should be in. Default: 'running'
  • service_enable: Whether the service should be enabled. Default: true

ds_389::ssl

  • cert_name: The nickname of the SSL cert to use. Required.
  • root_dn: The bind DN to use when calling ldapmodify. Required.
  • root_dn_pass: The password to use when calling ldapmodify. Required.
  • server_host: The host to use when calling ldapmodify. Default: $::fqdn
  • server_port: The port to use when calling ldapmodify. Default: 389
  • server_ssl_port: The port to use for SSL traffic. Default: 636
  • user: The owner of the created ldif file. Default: $::ds_389::user
  • group: The group of the created ldif file. Default: $::ds_389::group
  • minssf: The minimum security strength for connections. Default: 0
  • ssl_version_min: The minimum TLS version to allow. Default: 'TLS1.1'

Limitations

This module is currently tested and working on RedHat and CentOS 6, and 7, Debian 8, and 9, Ubuntu 14.04, and 16.04 systems.

Development

This module was developed with PDK.

Pull requests welcome. Please see the contributing guidelines below.

Contributing

  1. Fork the repo.

  2. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate.

  3. Add a test for your change. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, please add a test.

  4. Make the test pass.

  5. Push to your fork and submit a pull request.

puppet-ds_389's People

Contributors

spacepants avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

puppet-ds_389's Issues

Beaker acceptance tests failing for debian-82-x64.yml and ubuntu-server-1404-x64.yml due to non-patched bugs with 389-ds-base package from base system repositories

Hello,

I've been adding some new functionality to this module and will be submitting a pull request very soon. However, one thing I noticed is that the following beaker acceptance tests are now failing and I have figured out why. It's because we need 389-ds-base >= 1.3.4

These are failing with the same issue:

It is failing because the base 389-ds-base package that comes from the default repositories on Ubuntu or Debian is suffering from this bug https://pagure.io/389-ds-base/issue/48316. Yes, we could patch it but I don't think that is wise to do for this module. Instead, I'm thinking the next best course of action is to create a custom fact for this module so that we can we can better handle when things might go awry from upstream package differences across different operating systems. It will also give us the ability to fail fast if a version of the 389-ds-base package is not a supported or a tested version. What are your thoughts?

But yeah, otherwise, I'm unable to write beaker acceptance tests for those two test environments noted above because there is no easy fix unless we re-create 389-ds-base and all it's associated deps for beaker testing. That just sounds way to tedious and error prone. Compiling from source would also be difficult to do as a pre-step during the beaker test suite. The 389 packages do not seem to be patched for those two distros above so I'm wondering if should update the metadata.json to say we only support Ubuntu 16.04 and above and 389-ds-base >= 1.3.4?

'Add trust for server cert' cannot find cert with $ssl['cert_name']

If an instance is setup with SSL, using pre-existing files, there is a mismatch between the certificate name used to export the bundle into the pkcs12 file and the name used later to identify that cert during the 'Add trust for server cert' step. The first step is using the server name and the second the $ssl['cert_name']

Two excerpts from the debug run of the puppet agent:

Info: Concat[prod_cert_bundle]: Scheduling refresh of Exec[Create pkcs12 cert: prod]
Debug: ExecCreate pkcs12 cert: prod: Executing 'openssl pkcs12 -export -password pass:supersecret -name VW-ESXVM-S-3-LAP08-US.example.com -in /etc/ssl/prod-bundle.pem -out /etc/ssl/prod.p12'
Debug: Executing: 'openssl pkcs12 -export -password pass:supersecret -name VW-ESXVM-S-3-LAP08-US.example.com -in /etc/ssl/prod-bundle.pem -out /etc/ssl/prod.p12'

Debug: ExecAdd trust for server cert: prod: Executing check 'certutil -L -d /etc/dirsrv/slapd-prod | grep "identcert" | grep "u,u,u"'
Debug: Executing: 'certutil -L -d /etc/dirsrv/slapd-prod | grep "identcert" | grep "u,u,u"'
Debug: ExecAdd trust for server cert: prod: Executing 'certutil -M -n "identcert" -t u,u,u -d /etc/dirsrv/slapd-prod'
Debug: Executing: 'certutil -M -n "identcert" -t u,u,u -d /etc/dirsrv/slapd-prod'
Notice: /Stage[main]/Profiles::Ldap_server/Ds_389::Instance[VW-ESXVM-S-3-LAP08-US]/Exec[Add trust for server cert: prod]/returns: certutil: could not find certificate named "identcert": SEC_ERROR_BAD_DATABASE: security library: bad database.
Error: 'certutil -M -n "identcert" -t u,u,u -d /etc/dirsrv/slapd-prod' returned 255 instead of one of [0]
Error: /Stage[main]/Profiles::Ldap_server/Ds_389::Instance[VW-ESXVM-S-3-LAP08-US]/Exec[Add trust for server cert: prod]/returns: change from 'notrun' to ['0'] failed: 'certutil -M -n "identcert" -t u,u,u -d /etc/dirsrv/slapd-prod' returned 255 instead of one of [0]

I'd like to add admin functionality and submit a pull request?

Hello,

I'm really impressed by your module and would like to contribute setting up the admin-serv creation as a feature toggle so that folks can also install the 389 DS admin server and manage that configuration as well. Would you be willing to accept a pull request if I follow your contributing guidelines and write unit and acceptance tests?

Hope you are having a good week and thanks again for such awesome module with documentation, tests, functionality that works because it's hard to find stuff like this that actually works.

/etc/sysconfig is not present on Debian (based) systems

Creating a instance on a Ubuntu 16.04 system, results in this error message:

Error: Could not set 'present' on ensure: No such file or directory @ rb_sysopen - /etc/sysconfig/dirsrv.systemd at /etc/puppetlabs/code/environments/production/modules/ds_389/manifests/install.pp:36
Error: Could not set 'present' on ensure: No such file or directory @ rb_sysopen - /etc/sysconfig/dirsrv.systemd at /etc/puppetlabs/code/environments/production/modules/ds_389/manifests/install.pp:36
Wrapped exception:
No such file or directory @ rb_sysopen - /etc/sysconfig/dirsrv.systemd
Error: /Stage[main]/Ds_389::Install/Ini_setting[dirsrv ulimit]/ensure: change from 'absent' to 'present' failed: Could not set 'present' on ensure: No such file or directory @ rb_sysopen - /etc/sysconfig/dirsrv.systemd at /etc/puppetlabs/code/environments/production/modules/ds_389/manifests/install.pp:36

In this code block, /etc/sysconfig should be a param, on Debian based systemd, this file can be found here: /etc/default/dirsrv.systemd

 if $::ds_389::params::service_type == 'systemd' {
    ini_setting { 'dirsrv ulimit':
      ensure  => present,
      path    => '/etc/sysconfig/dirsrv.systemd',
      section => 'Service',
      setting => 'LimitNOFILE',
      value   => '8192',
      require => Package[$::ds_389::package_name],
    }
  }
  else {
    file_line { 'dirsrv ulimit':
      ensure  => present,
      path    => '/etc/sysconfig/dirsrv',
      line    => 'ulimit -n 8192',
      require => Package[$::ds_389::package_name],
    }
  }

No default OU and org entries are enabled when installing for the first time

I'm not sure if this is intentional or if I'm just missing something. I have a feeling it's me because it's been a really long time since I have done anything with LDAP but I've been scratching my head this afternoon on why my freshly installed dirsrv instance has no OU after the following two steps:

$instances = {
  'example' => {
    root_dn      => 'cn=Directory Manager',
    root_dn_pass => 'supersecret',
    suffix       => 'dc=example,dc=com',
    cert_db_pass => 'secret',
    server_id    => 'vagrant-ldap-01',
  }
}

include ::ds_389

create_resources(::ds_389::instance, $instances)

And then run as

 sudo /opt/puppetlabs/puppet/bin/puppet apply --modulepath $PWD/modules --verbose --detailed-exitcodes /tmp/site.pp

....

Everything installs successfully, the services are enabled and running. But when I run the validation command:

$ ldapsearch -x -b "dc=example,dc=com"

# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1

Which may be expected but I cannot find a document that actually works that tells me how to actually populate the DS schema properly for my OU, groups, users..etc. I'm sure I just need to do some more reading but I'm wondering what your thoughts are about adding these three options

slapd.AddOrgEntries=Yes slapd.AddSampleEntries=No slapd.InstallLdifFile=suggest

to the exec line found here: https://github.com/spacepants/puppet-ds_389/blob/master/manifests/instance.pp#L61?

Do you think adding those options would help others or do have these options below actually cause people grief in larger setups? I'm just trying to mimic the behavior for this module to install exactly likesetup-ds-admin.pl or setup-ds.pl if run by hand without any other flags.

nsslapd-minssf - Default setting

Hi,

The default setting for nsslapd-minssf provided bij 389 Directory Server is 0
But your template is using a default of 128. This means that only secured connection with a higher encryption then 128 is supported.
I would suggest to add a new variable and change the template to use the variable instead of using a static value.
nsslapd-minssf: 128

Information: http://www.port389.org/docs/389ds/howto/howto-use-ssf-restrictions.html#minimum-ssf-usage

Patch:
minssf.patch.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.