Giter VIP home page Giter VIP logo

voxpupuli / puppet-snmp Goto Github PK

View Code? Open in Web Editor NEW
35.0 43.0 131.0 675 KB

Puppet module to manage Net-SNMP.

Home Page: https://forge.puppet.com/puppet/snmp

License: Apache License 2.0

Ruby 65.21% Puppet 26.38% HTML 8.41%
bsd-puppet-module linux-puppet-module puppet hacktoberfest centos-puppet-module debian-puppet-module freebsd-puppet-module oraclelinux-puppet-module redhat-puppet-module sles-puppet-module

puppet-snmp's People

Contributors

alexandary avatar alexjfisher avatar amateo avatar bastelfreak avatar blackknight36 avatar cche58 avatar coreone avatar dan33l avatar dhoppe avatar ekarlso avatar ekohl avatar elmobp avatar erinn avatar geoffdavis avatar ghoneycutt avatar hbog avatar hdep avatar jrwesolo avatar kajinamit avatar kenyon avatar olifre avatar pawel-kuwalek avatar razorsedge avatar root-expert avatar silug avatar smoeding avatar smortex avatar traylenator avatar vstone avatar zilchms avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

puppet-snmp's Issues

Docs are unclear about replacement for ro_community et al

The docs warn that

The parameters ro_community, rw_community, ro_network, and rw_network
will be removed in version 4.0.0 of this module.

Could you give a brain-dead example or two of what parameters should be used instead? To use the Reddit phrase... explain it to me like I'm 12 years old. Thanks! (TBH, I think the com2sec stuff in the net-snmp package is badly documented in the first place.)

snmpwalk fails after installing this module

Hi ,

I install this module with the following config:

snmp::snmpv3_user { 'user':
authtype => 'MD5',
authpass => 'authpass',
privtype => 'DES',
privpass => 'privpass',
}
class { 'snmp':
agentaddress => [ 'udp:161'],
ro_network => '0.0.0.0' ,
contact => 'it-team@domain',
location => 'US',
snmpd_config => [ 'rouser user' ],
}

This installes the snmp package successfully and then when i run snmpwalk from a different host, it fails.

Any idea ??

rouser in snmpd.conf missing for v3 auth

Hi,

I am currently testing this module with Debian 7 and SNMP v3 auth, unfortunately it does not work as it does not add the "rouser" parameter into the snmpd.conf file. Here is my puppet manifest:

class { 'snmp':
agentaddress => [ 'udp:161', ],
contact => '[email protected]',
location => 'Phoenix, AZ',
}

snmp::snmpv3_user { 'myv3user':
authpass => 'authpass',
privpass => 'privpass',
}

This should actually add the "rouser myv3user" line to snmpd.conf but it doesn't. As such I get the following problem:

$ snmpwalk -v3 -u myv3user -l authNoPriv -a SHA -A authpass -X privpass localhost

Error in packet.
Reason: authorizationError (access denied to that object)

Let me know if you need more details!
Thanks

Needs to be updated to support Ubuntu 18

On ubuntu 18.04, i'm getting the following due to the fact that the username appears to have changed.

Error: Could not find user snmp
Error: /Stage[main]/Snmp/File[var-net-snmp]/owner: change from 'Debian-snmp' to 'snmp' failed: Could not find user snmp
Error: Could not find group snmp
Error: /Stage[main]/Snmp/File[var-net-snmp]/group: change from 'Debian-snmp' to 'snmp' failed: Could not find group snmp

smuxsocket disabling

Hi
On CentOS 7.1.1503 snmpd listens on tcp port 199 by default. I tried to switch it off via startup flags but unfortunately these get ignored. Specifically "-I -smux" From the little reading I have done this does not seem to be widely used and is turned off on Ubuntu 14. The only way to disable it is by giving it the wrong configuration:
smuxsocket 1.0.0.0

Now at the moment this is not surfaced as a parameter in the module. Before I add it as an option in a PR, I just wanted to get an opinion on whether it is worth adding. I did not see an option for adding arbitrary config, but it might be due to lack of coffee early in the morning.

Regards

CentOS 7.1 breaks params.rb

    $majdistrelease = regsubst($::operatingsystemrelease,'^(\d+)\.(\d+)','\1')

Does not work on CentOS 7.1.1503. That variable does not seem to exist.

lsbdistdescription => CentOS Linux release 7.1.1503 (Core)
lsbdistrelease => 7.1.1503
lsbmajdistrelease => 7
lsbminordistrelease => 1

Thus you get:

Mar 31 17:43:10 b0c008ash2001 puppet-user[42116]: comparison of String with 5 failed at /var/lib/puppet/repo/modules/snmp/manifests/params.pp:246 on node b0c008ash2001.mgmt.symcpe.net

TIA,

Creating snmpv3 users on loaded system fails

Sometimes when creating an snmpv3 user fails because the service snmpd isn't finished stopping when the create user command is issued. This is due to the fact that the 'service stop snmpd' command send a signal which is processed asynchronously.

To fix this, I added a little delay in the create user command

command => "${service_cmd} ; sleep .5; echo "${cmd}" >>${snmp::params::var_net_snmp}/${daemon}.conf && touch ${snmp::params::var_net_snmp}/${title}-${daemon}",

This solved the problem on all my hosts.

RFC-standard MIBS on Debian / Ubuntu

Hello,

I saw you had an item listed as an issue in your README, pertaining to RFC-standard MIBS on Debian. If you install the package 'snmp-mibs-downloader' and uncomment the following line in /etc/snmp/snmp.conf:

mibs :

You should now be able to do 'snmpwalk -v 2c -c public localhost system'

This package is available in the following versions of Debian:

  • wheezy
  • jessie
  • sid

Please not however that the package is in the 'non-free' section for Debian packages, and in the 'Multiverse' section for Ubuntu packages.

Are v3 user auth/priv password changes supported?

Looking through the snmpv3_user define, it does not appear that a change to the user's authentication or privacy passwords will be realized in the snmp configuration. It appears that the presence of the user is detected but not the credentials. Granted net-snmp makes this difficult and would requiring deriving the localized key for comparison on the usmUser line.

Problem with puppet v4

Hi,

This is module with problem puppet v4.

is it:

Error: Could not retrieve catalog from remote server: Error 500 on SERVER: {"message":"Server Error: Evaluation Error: Unknown variable: '::snmp_agentaddress'. at /etc/puppetlabs/code/environments/production/modules/snmp/manifests/params.pp:19:19 on node mail.tolidistribuidora.com.br","issue_kind":"RUNTIME_ERROR","stacktrace":["Warning: The 'stacktrace' property is deprecated and will be removed in a future version of Puppet. For security reasons, stacktraces are not returned with Puppet HTTP Error responses."]}
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run

Disable snmp v2 & v1

Hello,

I am currently testing your plugin which seems working fine on my system (debian 8).
Il only want to use snmpv3, this is working but the plugin is still generating some configuration about snmp v2, is there a way to disable this ?

Regards,

Unknown variable: 'snmp_agentaddress' error

I'm running your snmp module on a puppet 4 puppetserver (V 2.2.1) on Centos 6.7, and I'm getting the following error when I run:

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Evaluation Error: Unknown variable: '::snmp_agentaddress'. at /etc/puppetlabs/code/environments/test/modules/snmp/manifests/params.pp:19:19 on node it-lnx-01.enphaseenergy.com

I have created the following in my config files:

class { 'snmp':
  ro_community => 'password',
}

and

node /^it-lnx-\d+$/ {
  include common
  include mcollective::server
  include ::snmp
}

Any ideas what I'm doing wrong?

Thanks,
James "Zeke" Dehnert

mailto:[email protected] James "Zeke" Dehnert
-= Eschew Obfuscation =-
"Life is racing. Everything else is just waiting"

Using an array for ro_community breaks snmptrapd

manifests/init.pp says ro_community can be either strings or arrays of strings. When an array is provided, snmpd.conf is generated properly, but snmptrapd.conf does not loop over each community as expected, resulting in an invalid config file. [correction: ro_community6 is not relevant for snmptrapd.conf]

snmpd_options parameter does not work with Debian 9

The snmpd_options parameter of this module does not work anymore with Debian 9 (stretch). It looks like modifying the SNMPDOPTS environment variable directly in the /etc/defaults/snmpd file as does this module actually do is not taken in account anymore. Since Debian 9 uses systemd, the default SNMP daemon options are set in /lib/systemd/system/snmpd.service (in the ExecStart parameter). So starting from Debian 9 I think this module needs to use the systemd way in order to customise snmpd's options.

dynamic sysname?

Any way to have it dynamically add the hosts fqdn as the sysname in the snmpd.conf on the client? I need this in order for my autodiscovery to work with Observium.

Guidance using this module

Team,
Can someone provide me with some guidance in getting this module to work. I am using RHEL 7 and puppet 3.8. Thank you.

No such file or directory errors

There appears to be an error when this module is first run that causes errors to show up in our puppet reports. For example, the following errors occur during the first puppet run on a new host.

Error: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Error: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Wrapped exception:
No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock
Error: /Stage[main]/Snmp::Client/File[snmp.conf]/ensure: change from absent to present failed: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Info: Class[Snmp::Client]: Unscheduling all events on Class[Snmp::Client]Error: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Error: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Wrapped exception:
No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock
Error: /Stage[main]/Snmp::Client/File[snmp.conf]/ensure: change from absent to present failed: Could not set 'present' on ensure: No such file or directory @ dir_s_mkdir - /etc/snmp/snmp.conf20161121-20105-1teyemp.lock at /etc/puppetlabs/code/environments/ovirt_test/forge_modules/snmp/manifests/client.pp:85
Info: Class[Snmp::Client]: Unscheduling all events on Class[Snmp::Client]

Test cases are broken

Hi,

Unable to submit a PR as the test cases are broken before you even start.

As I a test I submitted a PR with just a change to the readme, which failed.

I'm sure contributors will fix issues with their own code but not with the master branch...

Prepare for release 4.0.0

This is the first release in VoxPupuli's puppet namespace.

Earlier versions of the module (razorsedge/snmp) stated that traditional access control and its parameters were deprecated and would be removed in version 4.0.0. Removing this feature has been deferred until at least version 5.

`ensure => absent` fails on el5/el6 if net-snmp-utils is installed

This module is able to install net-snmp-utils on el{56}.x by setting install_client => true but won't uninstall via ensure => absent unless install_client => true is also set. Eg.

Execution of '/bin/rpm -e net-snmp-5.3.2.2-17.el5_8.1.x86_64' returned 1: error: Failed dependencies: net-snmp = 1:5.3.2.2-17.el5_8.1 is needed by (installed) net-snmp-utils-5.3.2.2-17.el5_8.1.x86_64

This is a minor nitpick but I find the parameter misleading. Perhaps manage_client would be more intutive? Or would it make sense for ensure => absent to explicity set the same on snmp::client?

Multiple rocommunity,rwcommunity

Your module can only put one rocommunity and one rwcommunity line in snmpd.conf

I need to put more than one of each.

I may be able to contribute a solution

configuring extend parameters

Hi,

This is more a feaure request than a bug.

I recently started to deploy snmpd config using puppet. Unfortunately I saw that some hosts are failing, because custom cripts are used to check specific items.

Is there a possibility to add "extend" configuration parameters, or is there a reason why they have not been added?

For instance:
extend pcluster_check_space /bin/sh /usr/local/scripts/check_pcluster.sh space

Expectation would be for instance:
extend => ['pcluster_check_space /bin/sh /usr/local/scripts/check_pcluster.sh space',
],

br
Thomas

can't change value of snmp_com2sec (and potentially some other variables)

I've tried t change value of snmp_com2sec to something like "notConfigUser 127.0.0.1 public".

Problem is that's not passing check_array.
So effectively you can't change it to a string you need.

here is error log:

Error: Could not retrieve catalog from remote server: Error 400 on SERVER: "notConfigUser 127.0.0.1 public" is not an Array. It looks to be a String at /etc/puppet/blah-blah-blah/snmp/manifests/init.pp:319 on node test

Maybe it's not a best idea to use check_array for some of these variables.

ro_community not propogated to com2sec

not working for me for some reason, on PE 3.7

all I am trying is:

class { '::snmp':
  ro_community    => 'somestring',
}

the string gets propogated to the 'traditional access control'

# Traditional Access Control
#rocommunity somestring 127.0.0.1

but not to the com2sec section

# VACM Configuration
#       sec.name       source        community
com2sec notConfigUser  default       public

Provide a higher-level interface to snmpd

Most sites have simple needs that can be stated at a high level as:

  • read only:
    • "communitystring1", [list of cidr blocks]
    • "communitystring2", [list of cidr blocks]
  • read/write::
    • "communitystring3", [list of cidr blocks]
    • "communitystring4", [list of cidr blocks]

I propose a snmp::easy{} class that simply takes those values and generates the appropriate class parameters to snmp{}.

[Note: This will be super easy to implement in Puppet 4, but will make the module unusable by people that still use Puppet 3.x. When my site upgrades to Puppet 4, I'll be glad to contribute code.]

suggestion about ro_community removal planned in 5.0

Hello
I have noticed the expected removal of ro_community in favor of the VACM model for the 5.0 release and I'd like to speak in favor of keeping this setting. These post probably reflects a subjective point of view, but I ll try to be fair.

For what I saw on many snmpd setups, setting the community with a source restricted to a /32 host address (or even restricted to a dedicated management prefix) provides enough security.
Multiple sources are well managed by adding lines for the same SNMP community, as it s done with array arguments in the current 4.0 version. The per-view access control is a very fine grained tool but often, simple RO access to the root tree is OK.
I often saw setups with iptables used to restrict access rather than the VACM configuration model.

It keep configuration files clear and easy to debug, and integration in external/custom ENCs is very easy.
Currently, the rocommunity/rwcommunity settings in snmpd.conf is not deprecated in the net-snmp project.

Personally, I find the complexity of VACM isn't worth the benefit it could bring. As time flows, SNMP monitoring needs on hosts will probably lose some market shares, being replaced by "higher level" protocols and custom agents, thus I think that keeping this module simple to use and the opportunity to use the simple security model is a good thing.

Thanks for reading, and please feel free to comment.

Future parser and puppet-snmp

...gives following error:
Oct 2 17:38:17 puppet puppet-master[32215]: Illegal variable name, The given name 'Doptions' does not conform to the naming rule /^((::)?[a-z]w_)((::)?[a-z]w*)$/ at /etc/puppet/modules/snmp/manifests/snmpv3_user.pp:68:24

Probably should be as easy as renaming few vars?

ro_community cannot be set to 'undef' to remove from ERB template

Hi,

Presently in the snmpd.conf ERB template, ro_community and the others are all tested for 'nil' value before outputting the content - this is fine. However the way the parameters are constructed with the ENC backend and the hard coded default there is no possible way to set the variable to undef and consequently skip its output.

Can I suggest checking for both nil and size > 0 as this would allow forcefully disabling the output of those parameters?

I will issue a pull request since it is just a template change.

cannot disable VACM

The default behavior force to have a VACM configuration, which enable answers (but empty) on "public" community.
Allowing empty configuration would permit to remove the VACM lignes from configuration file, when it s not needed.

Failure to set authpass/privpass containing a dollar sign

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: 5.5.x
  • Ruby: 2.4.4
  • Distribution: Debian 9
  • Module version: 4.1.0

How to reproduce (e.g Puppet code you use)

Use authpass/privpass containing a '$' like this:

snmp::snmpv3_user { 'myuser':
  authpass => '1234$auth',
  privpass => '5678$priv',
}

What are you seeing

Puppet tries to update the snmpv3 user data at each run.

What behaviour did you expect instead

Puppet should update the snmpv3 user data only once.

Any additional information you'd like to impart

I think the problem is that the dollar sign is interpreted as the start of a variable and the value (maybe empty) is interpolated. Therefore the hash is calculated for a different password and Puppet tries to do the same next time because the hashes do not match.

I believe I traced this down to the place in snmpv3_user.pp where the exec resource is used to create the config entry:

    exec { "create-snmpv3-user-${title}":
      path    => '/bin:/sbin:/usr/bin:/usr/sbin',
      # TODO: Add "rwuser ${title}" (or rouser) to /etc/snmp/${daemon}.conf
      command => "service ${service_name} stop ; sleep 5 ; \
echo \"${cmd}\" >>${snmp::params::var_net_snmp}/${daemon}.conf",
      user    => 'root',
      require => [ Package['snmpd'], File['var-net-snmp'], ],
      before  => Service[$service_name],
    }

The Puppet variable ${cmd} contains the line to be added to the config file. The value is given to the shell using double quotes which tells the shell to look and interpret special chars. If the value of the ${cmd} variable contains something like $x then the shell will replace that with the value of the shell variable x. The password added to the configuration file is therefore not the correct password.

I see two possible fixes here:

  • Use single quotes so the shell does not try to interpret the value.
  • Replace the exec with something better, e.g. a service resource to stop the service and a file_line resource (from stdlib) to add the config line. Additional bonus points: the service resource would not depend on the service executable (is that even available everywhere?). Also the service could only be stopped once when multiple SNMP users are updated at the same time.

Thoughts/comments?

Create SNMPv3 user with keys (hashes) in lieu of passphrases

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: 5.5.x
  • Ruby: 2.4.4
  • Distribution: CentOS 7, CentOS 6
  • Module version: v4.1.0

How to reproduce (e.g Puppet code you use)

snmp::snmpv3_user only allows a user to be specified with plain text authpass and privpass passphrases. This means that these passphrases will exist in either a Puppet manifest or a Hieradata file. That persistence has been identified as a security risk.

Per the snmpd.conf man page, the createUser directive used in https://github.com/voxpupuli/puppet-snmp/blob/v4.1.0/manifests/snmpv3_user.pp#L42 and https://github.com/voxpupuli/puppet-snmp/blob/v4.1.0/manifests/snmpv3_user.pp#L43 does have a form that allows the passphrase hashes to be specified instead of the passphrases. That form requires the use of the '-l' or '-m' options.
Unfortunately, I cannot see a way to specify/inject those options in the existing sinmp::snmpv3_user code.

What are you seeing

Plain text passphrases persisted in manifests or Hieradata files.

What behaviour did you expect instead

Ability to add a user with hashed passphrases instead of plain text passphrases, so that hashed passphrases are persisted in manifests or Hieradata files.

Also, since the logic to generate these salted hashes is already available in a combination of the snmpv3_user fact and the snmp::snmpv3_usm_hash function, as a bonus, it would be really helpful if that code was also packaged a standalone salted-hash-generator script.

Output log

N/A

Any additional information you'd like to impart

$facts['networking']['fqdn'] not present on FreeBSD

Affected Puppet, Ruby, OS and module versions/distributions

  • Puppet: 4.10.12
  • Ruby: 2.4.4p296
  • Distribution:
  • Module version: 4.1.0

How to reproduce (e.g Puppet code you use)

Install on FreeBSD

What are you seeing

Failure to compile on FreeBSD 11.2 when using 4.1.0 of this module and stdlib 5.1.0

What behaviour did you expect instead

Cheap workaround may be...

$sysname = $facts['networking']['fqdn'] ? {
  undef => $facts['fqdn'],
  default => $facts['networking']['fqdn']
}

But I am not sure that would work. The fundamental problem is the array key(s) cannot be looked up when $networking is undef. Perhaps simply use $facts['fqdn'] for now?

Output log

Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Operator '[]' is not applicable to an Undef Value. at /etc/puppetlabs/code/environments/development/modules/snmp/manifests/params.pp:23:14 on node stsdevf.ucsd.edu
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run

Any additional information you'd like to impart

/usr/local/bin/facter -p fqdn resolves.
/usr/local/bin/facter -p networking does not.

Not possible to not start snmptrapd service

On RedHat systems, there doesn't seem to be a way to start snmpd without also starting snmptrapd. The module enables both or neither. If I set:

    trap_service_ensure => 'stopped',
    trap_service_enable => false,

snmptrapd still gets started.

Is the intentional? Is it bad to run snmpd without snmptrapd? We don't do anything with traps in our environment.

Release the current version on the forge

We're currently just starting to use the module and it would be useful if the current version would at least be released to make future upgrades (and possibly development) more easily

File permissions do not match the ones of the net-snmp

Hi,

After configuring the snmp services via your puppet module, the permissions of the following files do not match the ones of the net-snmp software rpm.

[root@rhtestsrv1-d ~]# rpm -Va | grep '^.M'
SM5....T.  c /etc/snmp/snmpd.conf
SM5....T.  c /etc/snmp/snmptrapd.conf

The puppet module sets the perm to 644 instead of 600.

Could it be changed in a future release of the module?
So that I won't receive any alerts in reports from SCAP.

Best regards,
Yannick

`extemds` variable typo

$snmp_extends = getvar('::snmp_extends')
if $snmp_extends {
$extemds = $::snmp_extends ### it has to be $extends
} else {
$extends = []
}

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.