{ "info": { "author": "Rob Crittenden", "author_email": "rcritten@redhat.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: OpenStack", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Topic :: Utilities" ], "description": "novajoin Package\n==================\n\nThis Python package provides a dynamic vendordata plugin for the OpenStack\nnova metadata service to manage host instantiation in an IPA server.\n\nIt consists of two services:\n\n - REST service\n - notification listener\n\nThe REST service will respond to dynamic requests from the nova metadata\nserver. This is used to add hosts into IPA.\n\nThe notification listener will handle instance delete requests and remove\nthe appropriate host from IPA as well as floating IP associate and\ndisassociate requests and update IPA DNS.\n\nBuild\n=====\n\nIn this directory, run::\n\n python setup.py build\n\n\nInstallation\n============\n\nIn this directory, run::\n\n python setup.py install\n\n\nPackage Requirements\n====================\n\nBeyond those packages normally installed by Openstack, these are also\nrequired::\n\n python-ipalib\n python-ipaclient\n\nThese may be pip-installable but still require other system packages\nlike `krb5-devel` to be present and may not be compatible with your\nFreeIPA installation, so it is best to install them with your system\npackage manager. Functional tests are configured to run against\nsystem packages found on RHEL/CentOS/Fedora.\n\n\nConfiguration\n=============\n\nThere are two installation scenarios:\n\n1. Triple-O Quickstart (Pike and above)\n\nThis is primary use-case to date. In this scenario the heat and\npuppet code manages most of the configuration. There is even some\ncode to configure everything if you're willing to provide the\nIPA admin password.\n\nIf not you can pre-create the entries needed by running this on\nany machine that has access to your IPA server. It can be\nrun from a git clone of novajoin by setting\nPYTHONPATH=/path/to/novajoin if you'd like::\n\n novajoin-ipa-setup --precreate --principal admin --password password \\\n --server ipa.example.com --realm EXAMPLE.COM --domain example.com \\\n --hostname undercloud.example.com\n\nThe machine executing this script does NOT need to be enrolled as\nan IPA client.\n\nThe output from the script is the OTP you'll set in undercloud_ipa_otp\nin the yaml configuration for OOOQ.\n\nThe idea here is that the undercloud node is pre-created and an OTP\ngenerated. The OOOQ script knows how to enroll hosts and will pass this\nOTP onto ipa-client-install, retrieve the keytab for the novajoin\nservice principal and configure and start the services. In OOOQ this is\ndone by setting enable_tls_everywhere to true and and prepare_novajoin\nto false.\n\nnovajoin-ipa-setup will configure the project name to be service. This\nmay not match your installation. Adjust as needed.\n\n2. Manual setup\n\nIt is also possible to setup novajoin within an existing OpenStack\ndeployment (I've done this in devstack, for example).\n\nThe machine running the novajoin service needs to be enrolled\nas an IPA client.\n\nRun novajoin-install to install and configure the plugin on a\npre-installed nova server.\n\nnova currently needs to be manually configured to enable the\nnovajoin REST service and enable notifications in\n**/etc/nova/nova.conf**::\n\n [api]\n vendordata_providers = StaticJSON, DynamicJSON\n vendordata_dynamic_targets = 'join@http://127.0.0.1:9090/v1/'\n vendordata_dynamic_connect_timeout = 5\n vendordata_dynamic_read_timeout = 30\n vendordata_jsonfile_path = /etc/novajoin/cloud-config-novajoin.json\n\n [notifications]\n notify_on_state_change = vm_state\n notification_format = unversioned\n\n [oslo_messaging_notifications]\n ...\n topics=notifications,novajoin_notifications\n\n.. note::\n Notifications have to be also enabled and configured on nova computes!\n See also information about enabling versioned and neutron notifications\n in the `Notification listener Configuration`_ section below.\n\nNovajoin enables keystone authentication by default, as seen in\n**/etc/novajoin/join-api-paste.ini**. So credentials need to be set for\nnova to be able to communicate with novajoin. This we can set in the\n``[vendordata_dynamic_auth]`` section of **/etc/nova/nova.conf**::\n\n [vendordata_dynamic_auth]\n #\n # Options within this group control the authentication of the vendordata\n # subsystem of the metadata API server (and config drive) with external\n # systems.\n\n auth_type = password\n password = < service user password >\n username = < service user >\n project_name = < service project >\n user_domain_name = < service user domain >\n project_domain_name = < service project domain >\n os_region_name = < region >\n\nIt is possible to just use the nova credentials here; or create a user just for\nthis. So choose depending on your requirements.\n\nPre-requisites\n--------------\n\nCloud-init 0.7.6+ is required to retrieve dynamic metadata when\nconfig_drive is True. 0.7.9 does not seem to work with OOOQ.\n\nYou will need the IPA admin password, or an account that can\nadd privileges, permissions, roles and can retrieve keytabs.\n\nYou will need to provide Openstack credentails in the environment\nso that the glance metadata upload can occur.\n\nThis will:\n\n- copy the cloud-init and enrollment script to **/etc/novajoin**\n- obtain a keytab to be used to authenticate against IPA when\n doing host management\n- call out to a script to create the requisite permissions and\n role in IPA\n- add the IPA metadata to the glance metadata service\n\nThe nova-api service will need to be manually restarted.\n\nThe installer takes the following options::\n\n --hostname: use this value as the FQDN of the server.\n --user: user that the nova service runs as. This is needed to\n set filesystem permissions\n --principal: the user used to configure IPA integration: create permissions,\n get the keytab, etc. Default is the IPA admin account.\n --password: the password for the principal. If this is not set the the\n password is obtained interactively\n --password-file: the file containing the password for the principal rather\n than passing it interactively or via the command-line\n\n\nMetadata REST Service Configuration\n===================================\n\nThe REST service is configured in **/etc/novajoin/join.conf** in the DEFAULT\nsection. It provides the following options:\n\n- join_listen_port: The TCP port to listen on. Defaults to 9090.\n- api_paste_config: The paste configuration file to use.\n- debug: Enable additional debugging output. Default is False.\n- auth_strategy: The authentication strategy to use\n- url: The JSON RPC URL to an IPA server, e.g. https://ipa.host.domain/ipa/json\n- keytab: The Kerberos keytab containing the credentails for the user\n nova will use to manage hosts. The default is **/etc/krb5.keytab**.\n- domain: The domain to associate with IPA hosts.\n- connect_retries: The number of times to attempt to contact the IPA\n server before failing.\n- project_subdomain: Use the project the instance is created in as the\n subddomain for the fully-qualified domain name. For example if\n the project is admin and the domain is example.com and the\n instance name is test the FQDN will be test.admin.example.com\n- normalize_project: A project name can contain values not allowed as a\n DNS label. This will convert invalid values to a dash (-)\n dropping leading and trailing dashes.\n\nOne must also configure the authtoken middleware in **/etc/novajoin/join.conf** as\nspecified in the `Keystone middleware documentation`_.\n\n.. _`Keystone middleware documentation`: https://docs.openstack.org/developer/keystonemiddleware/middlewarearchitecture.html#configuration\n\nNotification listener Configuration\n===================================\n\nThe only special configuration needed here is to configure nova to\nsend notifications to the novajoin topic in /etc/nova/nova.conf::\n\n [notifications]\n notify_on_state_change = vm_state\n notification_format = unversioned\n\n [oslo_messaging_notifications]\n ...\n topics = notifications,novajoin_notifications\n\nIn case of versioned notifications the configuration will look differently::\n\n [notifications]\n notify_on_state_change = vm_state\n notification_format = versioned\n versioned_notifications_topics = versioned_notifications,novajoin_notifications\n\n.. note::\n Notifications have to be also enabled and configured on nova computes!\n\nTo enable neutron notifications, in /etc/neutron/neutron.conf::\n\n [oslo_messaging_notifications]\n driver = messagingv2\n topics = notifications,novajoin_notifications\n\nIf you use notifications without changing the topic and ceilometer is\nrunning, then the notifications will be roughly split between the two\nservices in a round-robin fashion.\n\nUsage\n=====\n\nThis demonstrates how novajoin works once the services are installed,\nconfigured and running:\n\nSample usage from the command-line::\n\n $ openstack server create --flavor m1.tiny --image cirros-0.3.4-x86_64-uec test --property ipa_enroll=True\n $ ssh \n $ curl http://169.254.169.254/openstack/2016-10-06/vendor_data2.json\n $ id admin\n uid=#########(admin) gid=#########(admins) groups=#########(admins)\n\nThe curl output will include a \"join\" element in the returned dict.\nThis will contain a hostname and ipaotp value. These are used for\nenrollment with ipa-client-install via::\n\n # ipa-client-install -U -w --hostname \n\nThe provided cloud-init script should do all this for you, automatically\nfetching the OTP and enrolling the client.\n\nThis id command confirms that enrollment was successful.\n\nLogging\n=======\n\nThe REST novajoin-server service logs by default to\n/var/log/novajoin/novajoin-server.log\n\nThe notification listener service novajoin-notify logs by default to\n/var/log/novajoin/novajoin-notify.log\n\nA logrotate script for this is::\n\n /var/log/novajoin/*log {\n weekly\n rotate 14\n size 10M\n missingok\n compress\n }\n\n\nDesign\n======\n\nThere are quite a few moving parts in novajoin so here is a high-level\noverview of how it fits together.\n\nThe OpenStack Newton release added a new type of metadata to the nova\nmetadata service: dynamic metadata. This is metadata generated on-the-fly\nand not stored within nova (for example for security reasons).\n\nFor the case of enrolling a client into IPA using a One-Time Password (OTP)\nthe password needs to be generated when the IPA host created and then\nsomehow passed to the instance. This is done using dynamic metadata.\n\nThe basic sequence of events is:\n\n1. Instance creation is requested to nova, either via Horizon or the\n command-line.\n2. nova starts the instance and pushes down a cloud-init script provided\n by novajoin.\n3. cloud-init executes the provided script which installs the ipa-client\n package, then executes a script which retrieves the metadata from the\n nova metadata service[*]. This looks like:\n % curl http://169.254.169.254/openstack/2016-10-06/vendor_data2.json\n4. This request invokes the novajoin dynamic metadata service provided\n by the novajoin package. This is registered in **/etc/nova/nova.conf**.\n5. If the instance was created with the property ipa_enroll=True or\n the host image has this property set then a host in IPA is created and\n an OTP generated. The OTP and generated FQDN are returned to nova as a\n python dictionary. The data is returned from the metadata service as\n JSON. If the glance image has os_distro and os_version set in its\n metadata then this will be reflected in the IPA host.\n6. The script provided to cloud-init pulls out the OTP and FQDN and calls\n ipa-client-install\n\nThis results in an IPA-enrolled client with no user interaction.\n\nThe novajoin-notify service waits for notifications from nova that an\ninstance deletion has been completed. If that instance or image has the\nproperty ipa_enroll=True then the host is removed from IPA.\n\n.. note::\n In the case of config drive the metadata is retrieved and attached\n to the instance at boot time. cloud-init detects the config drive and\n reads its metadata from there.\n\n\nPackstack\n=========\n\nSome people have had difficulties deploying novajoin within Packstack.\nHere is how I did it on RHEL 7.4 using RHOSP 11 (Ocata).\n\nInstall packstack::\n\n # packstack \n\nConfigure host as an IPA client::\n\n # ipa-client-install ...\n\nGet the [keystone_authtoken] section from /etc/nova/nova.conf and call\nthe novajoin installer::\n\n # novajoin-install --user nova --keystone-auth-url \\\n --nova-password --project services\n\nAdd the novajoin user and group::\n\n # groupadd -r novajoin --gid 968\n # useradd -u 968 -r -g novajoin -G novajoin -d /var/lib/novajoin \\\n -s /sbin/nologin -c \"OpenStack novajoin Daemons\" novajoin\n\nCreate the log directory::\n\n # mkdir /var/log/novajoin\n # chown novajoin:novajoin /var/log/novajoin\n\nCopy the systemd unit files::\n\n # cp /usr/share/novajoin/*.service /usr/lib/systemd/system/\n # systemd daemon-reload\n\nRestart the necessary services::\n\n # systemctl restart openstack-nova-api novajoin-server novajoin-notify\n\nOrigin\n======\n\nThis builds on the work of Rich Megginson and Nathan Kinder. Rich\ndid the initial hooks implementation visible at\nhttps://github.com/richm/rdo-vm-factory/blob/master/rdo-ipa-nova\n\nCopyright and License\n=====================\n\nCopyright 2016 Red Hat, Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n not use this file except in compliance with the License. You may obtain\n a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n License for the specific language governing permissions and limitations\n under the License.\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/openstack/novajoin", "keywords": "", "license": "Apache License, Version 2.0", "maintainer": "", "maintainer_email": "", "name": "novajoin", "package_url": "https://pypi.org/project/novajoin/", "platform": "", "project_url": "https://pypi.org/project/novajoin/", "project_urls": { "Homepage": "https://github.com/openstack/novajoin" }, "release_url": "https://pypi.org/project/novajoin/1.2.0/", "requires_dist": [ "WebOb (>=1.7.1)", "Paste (>=2.0.2)", "Routes (>=2.3.1)", "six (>=1.10.0)", "python-keystoneclient (>=3.8.0)", "python-memcached (>=1.59)", "keystoneauth1 (>=3.3.0)", "oslo.concurrency (>=3.25.0)", "oslo.config (>=6.1.0)", "oslo.messaging (>=5.29.0)", "oslo.policy (>=1.30.0)", "oslo.serialization (!=2.19.1,>=2.18.0)", "oslo.service (!=1.28.1,>=1.24.0)", "oslo.utils (>=3.33.0)", "python-neutronclient (>=6.3.0)", "python-novaclient (>=9.1.0)", "python-cinderclient (>=3.3.0)", "python-glanceclient (>=2.8.0)", "keystonemiddleware (>=4.17.0)", "cachetools (>=2.0.0)" ], "requires_python": "", "summary": "Nova integration to enroll IPA clients", "version": "1.2.0" }, "last_serial": 5826130, "releases": { "1.0.10": [ { "comment_text": "", "digests": { "md5": "ca08fa2a7de721247672730e04b261f0", "sha256": "021ce5bd475a447b2e96f276c351ef3897947f9aa64dcbfeb79bcae88fe70765" }, "downloads": -1, "filename": "novajoin-1.0.10.tar.gz", "has_sig": false, "md5_digest": "ca08fa2a7de721247672730e04b261f0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51552, "upload_time": "2016-11-30T04:38:54", "url": "https://files.pythonhosted.org/packages/96/a1/2db10a8d3cd3a604475b607f115568caaa2bec7b5b733f4f5604450aac07/novajoin-1.0.10.tar.gz" } ], "1.0.11": [ { "comment_text": "", "digests": { "md5": "0e91c8e137e2cbce9da6579530d5c123", "sha256": "f396705de9bb67f9ead2255b682719bde3275390433f2a96f3a285b9fcac81cf" }, "downloads": -1, "filename": "novajoin-1.0.11-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "0e91c8e137e2cbce9da6579530d5c123", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 70775, "upload_time": "2017-02-14T18:31:19", "url": "https://files.pythonhosted.org/packages/88/97/e91d139d8407e5019afb9224f4646d0418802ad7a1f6d54b6c958fe0f2fd/novajoin-1.0.11-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4509632881f524c1748dde60c7789f31", "sha256": "1a5a0260614884a61fbfe6a8eb2173182aafcafc81a5a4547a2e856f4b1995ad" }, "downloads": -1, "filename": "novajoin-1.0.11.tar.gz", "has_sig": false, "md5_digest": "4509632881f524c1748dde60c7789f31", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 59089, "upload_time": "2017-02-14T18:31:21", "url": "https://files.pythonhosted.org/packages/53/34/d9ea04e82358e398a72cd4613fd61a1bf7313d533a7eab9f4ab15ce73a2d/novajoin-1.0.11.tar.gz" } ], "1.0.12": [ { "comment_text": "", "digests": { "md5": "64892bbb9b9b9361fd5e2823748cb594", "sha256": "2af6478f0a199c57e836db13d25edd54476c66890216caaea8e5e0268ef9f3e4" }, "downloads": -1, "filename": "novajoin-1.0.12-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "64892bbb9b9b9361fd5e2823748cb594", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 74183, "upload_time": "2017-03-30T14:52:37", "url": "https://files.pythonhosted.org/packages/53/c9/a8e39f076dc8b9e568c8a4b2f70026eccce8f5a5d0b6dd54eff65fba6095/novajoin-1.0.12-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d2795449b0bda51178b909d2d411b5c4", "sha256": "4c9789bee42a2633af0c6050f482728674577b30d06a1e01080bb2cee15271a2" }, "downloads": -1, "filename": "novajoin-1.0.12.tar.gz", "has_sig": false, "md5_digest": "d2795449b0bda51178b909d2d411b5c4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62563, "upload_time": "2017-03-30T14:52:38", "url": "https://files.pythonhosted.org/packages/f3/bc/1cbf14311725835e87898b2423077bfcca437cfcd14db1c8e61dced1150f/novajoin-1.0.12.tar.gz" } ], "1.0.13": [ { "comment_text": "", "digests": { "md5": "08b22b42f34255ae8dec59aec705f769", "sha256": "158b1a6715d1bb1ffe0bef232580b7c76f807cb76345eeb73daff6f391b64b19" }, "downloads": -1, "filename": "novajoin-1.0.13-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "08b22b42f34255ae8dec59aec705f769", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 73083, "upload_time": "2017-05-26T21:25:01", "url": "https://files.pythonhosted.org/packages/50/92/6efd502bb31506abc5bd1f0bb77358007444ff83de36c5f5c4be6629e548/novajoin-1.0.13-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a94a51bb85ee0e810373e43eb615e416", "sha256": "2313d0e25563da6af39d84aa8c44860fb8e9f1e2eebca687749cc7c9e92c6a92" }, "downloads": -1, "filename": "novajoin-1.0.13.tar.gz", "has_sig": false, "md5_digest": "a94a51bb85ee0e810373e43eb615e416", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66113, "upload_time": "2017-05-26T21:25:04", "url": "https://files.pythonhosted.org/packages/3b/ed/4844d27d6611c21ef052386cbc2d499221d64087534aaebb278963b20ebd/novajoin-1.0.13.tar.gz" } ], "1.0.14": [ { "comment_text": "", "digests": { "md5": "cce8fc77b35d6ced1a8508fa7ec5b29e", "sha256": "9d156fc3beb06143d9a6db68b1cfe84646ce45946738dc533b009a3d547beb5d" }, "downloads": -1, "filename": "novajoin-1.0.14-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "cce8fc77b35d6ced1a8508fa7ec5b29e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 73285, "upload_time": "2017-08-04T14:30:38", "url": "https://files.pythonhosted.org/packages/e5/5b/fcb62f3276a7e509705f7f529b74a1f1e3977f54c9e7c59f911dee9bd6a3/novajoin-1.0.14-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f4f34da675caf000efd3955a7e1685e6", "sha256": "d91b652306e01ee984594f712660c43f77aff4c8691b833d39b3c6dfec90b767" }, "downloads": -1, "filename": "novajoin-1.0.14.tar.gz", "has_sig": false, "md5_digest": "f4f34da675caf000efd3955a7e1685e6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 65292, "upload_time": "2017-08-04T14:30:42", "url": "https://files.pythonhosted.org/packages/09/ef/212b46ae24b0f17523336e9112d332ae1821e95e0c3ac4b1b1e15cbacf35/novajoin-1.0.14.tar.gz" } ], "1.0.15": [ { "comment_text": "", "digests": { "md5": "70cd80fce7ca850b40619b8705f90735", "sha256": "af71cbbba003c16ca03d6adbab5f5e2025e33371cd989cd612cd6c3d61283867" }, "downloads": -1, "filename": "novajoin-1.0.15-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "70cd80fce7ca850b40619b8705f90735", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 73406, "upload_time": "2017-08-21T19:12:54", "url": "https://files.pythonhosted.org/packages/59/1a/77f505c8b7ea4221398c2a5bedb0af1a80bd1d03004dc6cad1c21f70e77e/novajoin-1.0.15-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f6679d98b56b156036081bb25a6fa46e", "sha256": "992e9e45ed8f2e2b30348dbb512d20879f6d616df5875312e6a0b3f2a5e560f3" }, "downloads": -1, "filename": "novajoin-1.0.15.tar.gz", "has_sig": false, "md5_digest": "f6679d98b56b156036081bb25a6fa46e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 62854, "upload_time": "2017-08-21T19:12:58", "url": "https://files.pythonhosted.org/packages/c2/98/770ce3e66e13b2c9ca8f2aa85215e68df0337cdaba3ce94381c22c377d96/novajoin-1.0.15.tar.gz" } ], "1.0.16": [ { "comment_text": "", "digests": { "md5": "25704cf6ec23874996d41dedaf3bc174", "sha256": "a720e0bf125b16053590fed8d1f41fb07f7453d06d52e400ce56bdfadf089ae5" }, "downloads": -1, "filename": "novajoin-1.0.16-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "25704cf6ec23874996d41dedaf3bc174", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 76101, "upload_time": "2017-08-29T02:12:28", "url": "https://files.pythonhosted.org/packages/cf/6f/2c9498e8fb555884435ec25cddf51aa729532b756fe85d85049d0f0dc44b/novajoin-1.0.16-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0c07c5ef77f15ed8dfbfbb033eba80d4", "sha256": "7a8299210d28d5c7a1c6dd9477623af1c80719e4b9b7f3b065ac22c641706683" }, "downloads": -1, "filename": "novajoin-1.0.16.tar.gz", "has_sig": false, "md5_digest": "0c07c5ef77f15ed8dfbfbb033eba80d4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 64865, "upload_time": "2017-08-29T02:12:31", "url": "https://files.pythonhosted.org/packages/d7/12/8790035a93ec6734890dfa55792b71170413e0678a5a202f5c7551c8917b/novajoin-1.0.16.tar.gz" } ], "1.0.17": [ { "comment_text": "", "digests": { "md5": "3b3859d3dd67111bf59fbd232b765fa5", "sha256": "4efde0a3dc182fe1ccb38bdde11b4ed3edbdb24ed8ec869cbd7de4c27ef4c91b" }, "downloads": -1, "filename": "novajoin-1.0.17-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "3b3859d3dd67111bf59fbd232b765fa5", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 76793, "upload_time": "2017-09-19T15:28:03", "url": "https://files.pythonhosted.org/packages/f4/a0/372a7f61914504f8f8dc804c484a2393916206f076ae2a927e50e1bd946d/novajoin-1.0.17-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b5a53aea17ea16b7e53463833e1f234a", "sha256": "08cc25a49181e4573e3ed42a7869bc2a83ab7dd5d5bc399f834b5325f26a6209" }, "downloads": -1, "filename": "novajoin-1.0.17.tar.gz", "has_sig": false, "md5_digest": "b5a53aea17ea16b7e53463833e1f234a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66397, "upload_time": "2017-09-19T15:28:06", "url": "https://files.pythonhosted.org/packages/7d/66/d512734437615a16570c5eac616df4f7100a5b21b231d64e196c29643a2b/novajoin-1.0.17.tar.gz" } ], "1.0.18": [ { "comment_text": "", "digests": { "md5": "167a51d3848106d8821d2b0b62a261e2", "sha256": "1fa2953bce84d5d62efcb1413902f390cfb7195ec0df80b5e3be1a005b0641f2" }, "downloads": -1, "filename": "novajoin-1.0.18-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "167a51d3848106d8821d2b0b62a261e2", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 77327, "upload_time": "2018-02-22T15:13:39", "url": "https://files.pythonhosted.org/packages/61/d2/187cf700fec3260393735eb98195fecf849d8d6bcdb5210e1251a1e05e7f/novajoin-1.0.18-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d6f527a6e20abd45eb592f50f3d4a319", "sha256": "b98ac7c97a90aeea605cff35dac36c6025dd9bd9a4fe8c81d6eb3940c3017613" }, "downloads": -1, "filename": "novajoin-1.0.18.tar.gz", "has_sig": false, "md5_digest": "d6f527a6e20abd45eb592f50f3d4a319", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 67150, "upload_time": "2018-02-22T15:13:43", "url": "https://files.pythonhosted.org/packages/77/ec/01615ee055c6f35fde31a0e8dcb4c846c92bcbf5f52cb41db943f595c0ba/novajoin-1.0.18.tar.gz" } ], "1.0.19": [ { "comment_text": "", "digests": { "md5": "b5ed219c62985057c6e2437dcb866452", "sha256": "463d13d71d8ef975ae58ec9098a702ce8d4d1a7db228fc62836e54dd9dd5930e" }, "downloads": -1, "filename": "novajoin-1.0.19-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b5ed219c62985057c6e2437dcb866452", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 70907, "upload_time": "2018-08-24T19:35:42", "url": "https://files.pythonhosted.org/packages/af/42/58726c238344f79bafc606f257cea8d3efff6067a3d0d3568876e5ff519d/novajoin-1.0.19-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c4041c2b0698fdda18efaa5c6db62248", "sha256": "a5bf7eda1249a8c797d098d328d682e391c9ff97784c7be1503d4a40052465a2" }, "downloads": -1, "filename": "novajoin-1.0.19.tar.gz", "has_sig": false, "md5_digest": "c4041c2b0698fdda18efaa5c6db62248", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 66954, "upload_time": "2018-08-24T19:35:50", "url": "https://files.pythonhosted.org/packages/db/10/419d4c403f03a08934c7aac32cdb2b77770290386649717c7f63f512b04e/novajoin-1.0.19.tar.gz" } ], "1.0.20": [ { "comment_text": "", "digests": { "md5": "79279dd5b652ca4b27eb1584082620e0", "sha256": "d1f4a4e7922551e839c500dbd1418b6f57c9b0b6883bc3e1067ed0d49c21d203" }, "downloads": -1, "filename": "novajoin-1.0.20-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "79279dd5b652ca4b27eb1584082620e0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 75061, "upload_time": "2018-10-23T18:17:10", "url": "https://files.pythonhosted.org/packages/ca/f9/3aa2525b72630c6a21268431c28f1f67417544eb03aa68a37c2e1457feaa/novajoin-1.0.20-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "44a3b622f44d6d96a40782237a0ef8e4", "sha256": "7640701ddfb86ef6ea40c8aff0e775d24c8d23dcfc9ed4a03a6c423061974785" }, "downloads": -1, "filename": "novajoin-1.0.20.tar.gz", "has_sig": false, "md5_digest": "44a3b622f44d6d96a40782237a0ef8e4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 67012, "upload_time": "2018-10-23T18:17:13", "url": "https://files.pythonhosted.org/packages/4c/00/68aafd969471161f82401bb0a99bd3dfab3c8c609d352cd89d51bdc3644c/novajoin-1.0.20.tar.gz" } ], "1.0.21": [ { "comment_text": "", "digests": { "md5": "11cfec760265a3a94694f5f317eb7278", "sha256": "1cadea2debd7aab5d0706cb6a4b9b2db3308034fd3833836d2f177162c9cea76" }, "downloads": -1, "filename": "novajoin-1.0.21-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "11cfec760265a3a94694f5f317eb7278", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 75262, "upload_time": "2018-11-09T20:17:40", "url": "https://files.pythonhosted.org/packages/2c/39/d4a6b23be49b3ee460b57cb4b2698504d43d56064091e33518a49220ffaf/novajoin-1.0.21-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "777b906c9cd61c35137f98667b482fa4", "sha256": "d222773267d8f29a5c35a66601decab479bfc2210c63a224705a82362f76a462" }, "downloads": -1, "filename": "novajoin-1.0.21.tar.gz", "has_sig": false, "md5_digest": "777b906c9cd61c35137f98667b482fa4", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 65578, "upload_time": "2018-11-09T20:17:45", "url": "https://files.pythonhosted.org/packages/6c/3d/9862976fe38d3162ff0fce6db4f34a33c5bb33cf66db867cb2c48c007f78/novajoin-1.0.21.tar.gz" } ], "1.0.22": [ { "comment_text": "", "digests": { "md5": "a45f6155ef186bba65a0fa8016697f08", "sha256": "d67d9d92820f364c7efce9ae380d40ced7751815574a9b13c9283bb7d200be60" }, "downloads": -1, "filename": "novajoin-1.0.22-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a45f6155ef186bba65a0fa8016697f08", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 86797, "upload_time": "2018-12-13T16:49:09", "url": "https://files.pythonhosted.org/packages/02/b5/c40934378c4937c1ed228f23c485731867ab959254f0c2d8b98a01659e77/novajoin-1.0.22-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3b9a6e6574d89fa0fb7f3883a102d0c2", "sha256": "708a3b723f73a99252a71e91a00567478dcabb7a82a10193041b591b73e38145" }, "downloads": -1, "filename": "novajoin-1.0.22.tar.gz", "has_sig": false, "md5_digest": "3b9a6e6574d89fa0fb7f3883a102d0c2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 77134, "upload_time": "2018-12-13T16:49:12", "url": "https://files.pythonhosted.org/packages/87/7f/aa0cc9f252cc306cf507cd94f630f55cc88057607b26cca73f96e363d5ef/novajoin-1.0.22.tar.gz" } ], "1.0.9": [ { "comment_text": "", "digests": { "md5": "05b235680b1f6898f1315267c1e00615", "sha256": "d4534cc48af920db807205c82ae0b0a2e53759f8445e7a33fb78efc0be272848" }, "downloads": -1, "filename": "novajoin-1.0.9.tar.gz", "has_sig": false, "md5_digest": "05b235680b1f6898f1315267c1e00615", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 51527, "upload_time": "2016-11-29T16:24:24", "url": "https://files.pythonhosted.org/packages/47/81/7df4e924e8af4cc1a47f7a357258f61d3727b1004e0f6a90fe830cff5bd7/novajoin-1.0.9.tar.gz" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "08a3937d8fd306e8ee90103413ef04e0", "sha256": "eb7f5bbc4fbb4d17eed9cd64cdcf48d0c03e7a9aac704cbf2a5bdf73f4f0327b" }, "downloads": -1, "filename": "novajoin-1.1.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "08a3937d8fd306e8ee90103413ef04e0", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 88097, "upload_time": "2019-01-10T17:53:54", "url": "https://files.pythonhosted.org/packages/1e/21/79b4ad3628c3c11d24baa91cf5e64ae0ff65290b1399d98ee5abb2da00f0/novajoin-1.1.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "fc2849dde809bcbcffae6fdb97916fb5", "sha256": "087e9694fdaa1d7ab129aabf0d94eb67d9a332158b56010a1a8c6c90d1dcfee6" }, "downloads": -1, "filename": "novajoin-1.1.0.tar.gz", "has_sig": false, "md5_digest": "fc2849dde809bcbcffae6fdb97916fb5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 81770, "upload_time": "2019-01-10T17:53:57", "url": "https://files.pythonhosted.org/packages/82/60/12b512523ac34e4e14cca51ba97a79320b08f3e5ea499f0b2c496d53b920/novajoin-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "a04ab64669103b6108edf89f455a5140", "sha256": "2707805aa5eaa4ae529223a59a0acd32d1862cff5129a0171b9e45e6b1cb6be3" }, "downloads": -1, "filename": "novajoin-1.1.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a04ab64669103b6108edf89f455a5140", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 86719, "upload_time": "2019-02-12T15:16:29", "url": "https://files.pythonhosted.org/packages/3a/bd/91cba1f52e3842707ce7b0b26f24346bb380254ec7bbccfe90a8a021847c/novajoin-1.1.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3eda1b7d0d30a93e612f280c8b068c45", "sha256": "a95e8d7663e9f250664da2550d17a6eb75965d8e903771c44745739939946bdc" }, "downloads": -1, "filename": "novajoin-1.1.1.tar.gz", "has_sig": false, "md5_digest": "3eda1b7d0d30a93e612f280c8b068c45", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 77385, "upload_time": "2019-02-12T15:16:37", "url": "https://files.pythonhosted.org/packages/3f/62/2a67522701e27cd2a71da76d8f9442455b4202ebe47bf8e39acd65f830a8/novajoin-1.1.1.tar.gz" } ], "1.2.0": [ { "comment_text": "", "digests": { "md5": "a3efdb344c69b5a8d27be974aff87d49", "sha256": "ffd34c65985ee6f6faef5857f7e9c20db5780eec55c1a3e846e983ff483c927f" }, "downloads": -1, "filename": "novajoin-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a3efdb344c69b5a8d27be974aff87d49", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 89785, "upload_time": "2019-09-13T14:53:31", "url": "https://files.pythonhosted.org/packages/da/fe/6bdcb11618324397bfbcba6e2eac2fe2c1c9da467621eb5f7cfb810e99c3/novajoin-1.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b523ee77476e358232466c60a74c7f51", "sha256": "e915a18f128812938c3c791a2cc3d29b5c57d31800c26eb4c9ca6b37695f0735" }, "downloads": -1, "filename": "novajoin-1.2.0.tar.gz", "has_sig": false, "md5_digest": "b523ee77476e358232466c60a74c7f51", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 79541, "upload_time": "2019-09-13T14:53:35", "url": "https://files.pythonhosted.org/packages/df/5f/44f3fb1f4d4bd1c86d0887c578453e56c332dcce74500e57872430c440aa/novajoin-1.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a3efdb344c69b5a8d27be974aff87d49", "sha256": "ffd34c65985ee6f6faef5857f7e9c20db5780eec55c1a3e846e983ff483c927f" }, "downloads": -1, "filename": "novajoin-1.2.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "a3efdb344c69b5a8d27be974aff87d49", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 89785, "upload_time": "2019-09-13T14:53:31", "url": "https://files.pythonhosted.org/packages/da/fe/6bdcb11618324397bfbcba6e2eac2fe2c1c9da467621eb5f7cfb810e99c3/novajoin-1.2.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b523ee77476e358232466c60a74c7f51", "sha256": "e915a18f128812938c3c791a2cc3d29b5c57d31800c26eb4c9ca6b37695f0735" }, "downloads": -1, "filename": "novajoin-1.2.0.tar.gz", "has_sig": false, "md5_digest": "b523ee77476e358232466c60a74c7f51", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 79541, "upload_time": "2019-09-13T14:53:35", "url": "https://files.pythonhosted.org/packages/df/5f/44f3fb1f4d4bd1c86d0887c578453e56c332dcce74500e57872430c440aa/novajoin-1.2.0.tar.gz" } ] }