├── .gitignore ├── Dockerfile ├── Dockerfile-demo ├── LICENSE ├── Makefile ├── README.md ├── ansible_playbook ├── __init__.py ├── deploy.yml ├── hosts ├── requirements.yml ├── roles │ └── skip │ │ ├── defaults │ │ └── main.yml │ │ └── tasks │ │ └── main.yml ├── runplaybook.py ├── shared │ └── after-symlink.yml ├── skip.yml └── version.yml ├── demo ├── Dockerfile-Tomcat ├── bootstrap.sh ├── clean_all.sh ├── docker-compose-common.yml ├── docker-compose.yml ├── files │ ├── code │ │ └── etc │ │ │ ├── ansible │ │ │ └── roles │ │ │ │ └── carlosbuenosvinos.ansistrano-deploy │ │ │ │ ├── .gitignore │ │ │ │ ├── .travis.yml │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── TESTING.md │ │ │ │ ├── Vagrantfile │ │ │ │ ├── ansible.cfg │ │ │ │ ├── defaults │ │ │ │ └── main.yml │ │ │ │ ├── docs │ │ │ │ ├── ansistrano-flow.png │ │ │ │ └── figure.md │ │ │ │ ├── example │ │ │ │ ├── my-app │ │ │ │ │ └── index.html │ │ │ │ └── my-playbook │ │ │ │ │ ├── ansible.cfg │ │ │ │ │ ├── deploy.yml │ │ │ │ │ ├── hosts │ │ │ │ │ └── rollback.yml │ │ │ │ ├── meta │ │ │ │ ├── .galaxy_install_info │ │ │ │ └── main.yml │ │ │ │ ├── tasks │ │ │ │ ├── anon-stats.yml │ │ │ │ ├── cleanup.yml │ │ │ │ ├── empty.yml │ │ │ │ ├── main.yml │ │ │ │ ├── rsync-deploy.yml │ │ │ │ ├── setup.yml │ │ │ │ ├── symlink-shared.yml │ │ │ │ ├── symlink.yml │ │ │ │ ├── update-code.yml │ │ │ │ └── update-code │ │ │ │ │ ├── copy.yml │ │ │ │ │ ├── copy_unarchive.yml │ │ │ │ │ ├── download.yml │ │ │ │ │ ├── download_unarchive.yml │ │ │ │ │ ├── git.yml │ │ │ │ │ ├── rsync.yml │ │ │ │ │ ├── s3.yml │ │ │ │ │ ├── s3_unarchive.yml │ │ │ │ │ └── unarchive.yml │ │ │ │ └── test │ │ │ │ ├── tasks │ │ │ │ ├── create-internal-paths.yml │ │ │ │ └── create-shared-paths.yml │ │ │ │ └── test.yml │ │ │ └── ssh │ │ │ └── ssh_config │ ├── db │ │ └── docker-entrypoint-initdb.d │ │ │ └── tars.sql │ ├── shared │ │ └── ssh │ │ │ ├── authorized_keys │ │ │ ├── id_rsa │ │ │ └── id_rsa.pub │ └── tomcat │ │ └── etc │ │ ├── ssh │ │ ├── ssh_host_rsa_key │ │ └── ssh_host_rsa_key.pub │ │ ├── supervisord.d │ │ ├── ssh.ini │ │ └── tomcat.ini │ │ └── yum.repos.d │ │ └── CentOS-Epel.repo └── init.sh ├── doc └── images │ ├── API-Application-C.png │ ├── API-Application-List.png │ ├── API-Group-C.png │ ├── API-Group-List.png │ ├── API-Group-RD.png │ ├── API-Group-U.png │ ├── API-Package-C.png │ ├── API-Package-List.png │ ├── API-Server-C.png │ ├── API-Server-List.png │ ├── Admin-Application-New.png │ ├── Admin-Application-RDL.png │ ├── Admin-Group-CU.png │ ├── Admin-Group-RDL.png │ ├── Admin-Overview.png │ ├── Admin-Package-New1-CU.png │ ├── Admin-Package-New2-1.png │ ├── Admin-Package-New2-2.png │ ├── Admin-Package-RDL.png │ ├── Admin-Server-CU.png │ ├── Admin-Server-RDL.png │ ├── Demo-Screenshots-Deployment-Configure.png │ ├── Demo-Screenshots-Deployment-Init.png │ ├── Demo-Screenshots-Deployment-Packages.png │ ├── Demo-Screenshots-Deployment.png │ ├── Demo-Screenshots-Web.png │ ├── Demo-Services.png │ ├── Development-Docker-Configure-DB.png │ ├── Development-Docker-Finish.png │ ├── Development-Docker-Services.png │ └── Development-Screenshots-Web.png ├── docker-compose-frontend.yml ├── docker-compose.yml ├── manage.py ├── requirements ├── base.txt ├── local.txt └── production.txt ├── rest_client ├── __init__.py ├── clients │ ├── __init__.py │ ├── core.py │ ├── es.py │ └── salt.py ├── decorators.py ├── exceptions.py └── utils.py ├── roll_engine ├── __init__.py ├── celery.py ├── constants.py ├── db.py ├── exceptions.py ├── factory.py ├── fsm │ ├── __init__.py │ ├── batch.py │ ├── deployment.py │ └── target.py ├── mixins.py ├── models │ ├── __init__.py │ ├── actions.py │ ├── base.py │ ├── batches.py │ ├── configs.py │ ├── deployments.py │ └── targets.py ├── tasks.py └── utils │ ├── __init__.py │ └── log.py ├── setup.cfg ├── setup.py ├── tars ├── __init__.py ├── api │ ├── __init__.py │ ├── decorators.py │ ├── filters.py │ ├── permissions.py │ ├── serializers │ │ ├── __init__.py │ │ ├── application.py │ │ ├── base.py │ │ ├── deployment.py │ │ └── server.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_application.py │ │ ├── test_deployment.py │ │ └── test_group.py │ ├── urls.py │ ├── utils.py │ └── views │ │ ├── __init__.py │ │ ├── application.py │ │ ├── deployment.py │ │ ├── log.py │ │ └── server.py ├── application │ ├── __init__.py │ ├── admin.py │ └── models.py ├── deployment │ ├── __init__.py │ ├── admin.py │ ├── constants.py │ ├── fsm.py │ ├── mixins.py │ ├── models │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── batches.py │ │ ├── configs.py │ │ ├── deployments.py │ │ └── targets.py │ ├── tasks.py │ └── templatetags │ │ ├── __init__.py │ │ └── app_filters.py ├── engine │ ├── __init__.py │ └── celery_app.py ├── exceptions.py ├── middleware │ └── __init__.py ├── server │ ├── __init__.py │ ├── admin.py │ ├── agency.py │ ├── lb.py │ ├── models.py │ └── verify.py ├── settings │ ├── __init__.py │ ├── base.py │ ├── docker.py │ ├── environments.py │ └── local.py.example ├── surface │ ├── __init__.py │ ├── decorators.py │ ├── static │ │ ├── .jsbeautifyrc │ │ ├── admin │ │ │ ├── img │ │ │ │ ├── changelist-bg.gif │ │ │ │ ├── changelist-bg_rtl.gif │ │ │ │ ├── default-bg-reverse.gif │ │ │ │ ├── default-bg.gif │ │ │ │ ├── deleted-overlay.gif │ │ │ │ ├── gis │ │ │ │ │ ├── move_vertex_off.png │ │ │ │ │ └── move_vertex_on.png │ │ │ │ ├── icon-no.gif │ │ │ │ ├── icon-unknown.gif │ │ │ │ ├── icon-yes.gif │ │ │ │ ├── icon_addlink.gif │ │ │ │ ├── icon_alert.gif │ │ │ │ ├── icon_calendar.gif │ │ │ │ ├── icon_changelink.gif │ │ │ │ ├── icon_clock.gif │ │ │ │ ├── icon_deletelink.gif │ │ │ │ ├── icon_error.gif │ │ │ │ ├── icon_searchbox.png │ │ │ │ ├── icon_success.gif │ │ │ │ ├── inline-delete-8bit.png │ │ │ │ ├── inline-delete.png │ │ │ │ ├── inline-restore-8bit.png │ │ │ │ ├── inline-restore.png │ │ │ │ ├── inline-splitter-bg.gif │ │ │ │ ├── nav-bg-grabber.gif │ │ │ │ ├── nav-bg-reverse.gif │ │ │ │ ├── nav-bg-selected.gif │ │ │ │ ├── nav-bg.gif │ │ │ │ ├── selector-icons.gif │ │ │ │ ├── selector-search.gif │ │ │ │ ├── sorting-icons.gif │ │ │ │ ├── tooltag-add.png │ │ │ │ └── tooltag-arrowright.png │ │ │ └── js │ │ │ │ ├── LICENSE-JQUERY.txt │ │ │ │ ├── SelectBox.js │ │ │ │ ├── SelectFilter2.js │ │ │ │ ├── actions.js │ │ │ │ ├── actions.min.js │ │ │ │ ├── admin │ │ │ │ ├── DateTimeShortcuts.js │ │ │ │ └── RelatedObjectLookups.js │ │ │ │ ├── calendar.js │ │ │ │ ├── collapse.js │ │ │ │ ├── collapse.min.js │ │ │ │ ├── core.js │ │ │ │ ├── inlines.js │ │ │ │ ├── inlines.min.js │ │ │ │ ├── jquery.init.js │ │ │ │ ├── jquery.js │ │ │ │ ├── jquery.min.js │ │ │ │ ├── prepopulate.js │ │ │ │ ├── prepopulate.min.js │ │ │ │ ├── timeparse.js │ │ │ │ └── urlify.js │ │ ├── bower.json │ │ ├── django_extensions │ │ │ ├── img │ │ │ │ └── indicator.gif │ │ │ └── js │ │ │ │ ├── jquery-1.7.2.min.js │ │ │ │ ├── jquery.ajaxQueue.js │ │ │ │ ├── jquery.autocomplete.js │ │ │ │ └── jquery.bgiframe.min.js │ │ ├── gulpfile.js │ │ ├── jre │ │ │ ├── jsvm.js │ │ │ └── src │ │ │ │ ├── main │ │ │ │ └── js │ │ │ │ │ ├── atom │ │ │ │ │ └── misc │ │ │ │ │ │ └── Launcher.js │ │ │ │ │ └── js │ │ │ │ │ ├── awt │ │ │ │ │ ├── Audo.js │ │ │ │ │ ├── Button.js │ │ │ │ │ ├── Canvas.js │ │ │ │ │ ├── Choice.js │ │ │ │ │ ├── Color.js │ │ │ │ │ ├── Component.js │ │ │ │ │ ├── Container.js │ │ │ │ │ ├── Date.js │ │ │ │ │ ├── Dialog.js │ │ │ │ │ ├── Field.js │ │ │ │ │ ├── Frame.js │ │ │ │ │ ├── GridPanel.js │ │ │ │ │ ├── Hidden.js │ │ │ │ │ ├── Image.js │ │ │ │ │ ├── Label.js │ │ │ │ │ ├── List.js │ │ │ │ │ ├── Menu.js │ │ │ │ │ ├── Panel.js │ │ │ │ │ ├── ProgressBar.js │ │ │ │ │ ├── Radio.js │ │ │ │ │ ├── Spinner.js │ │ │ │ │ ├── TabPanel.js │ │ │ │ │ ├── Text.js │ │ │ │ │ ├── TextArea.js │ │ │ │ │ ├── TextField.js │ │ │ │ │ ├── Time.js │ │ │ │ │ ├── Tree.js │ │ │ │ │ ├── TreePanel.js │ │ │ │ │ ├── Video.js │ │ │ │ │ └── Window.js │ │ │ │ │ ├── dom │ │ │ │ │ └── Document.js │ │ │ │ │ ├── io │ │ │ │ │ ├── Console.js │ │ │ │ │ ├── PrintWriter.js │ │ │ │ │ └── Writer.js │ │ │ │ │ ├── lang │ │ │ │ │ ├── Array.js │ │ │ │ │ ├── Boolean.js │ │ │ │ │ ├── Class.js │ │ │ │ │ ├── ClassLoader.js │ │ │ │ │ ├── ClassNotFoundException.js │ │ │ │ │ ├── CloneNotSupportedException.js │ │ │ │ │ ├── Error.js │ │ │ │ │ ├── EvalError.js │ │ │ │ │ ├── Exception.js │ │ │ │ │ ├── Function.js │ │ │ │ │ ├── IllegalAccessException.js │ │ │ │ │ ├── IllegalArgumentException.js │ │ │ │ │ ├── IllegalStateException.js │ │ │ │ │ ├── IndexOutOfBoundsException.js │ │ │ │ │ ├── InternalError.js │ │ │ │ │ ├── NoSuchFieldException.js │ │ │ │ │ ├── NoSuchMethodException.js │ │ │ │ │ ├── NullPointerException.js │ │ │ │ │ ├── Number.js │ │ │ │ │ ├── Object.js │ │ │ │ │ ├── RangeError.js │ │ │ │ │ ├── ReferenceError.js │ │ │ │ │ ├── RegExp.js │ │ │ │ │ ├── String.js │ │ │ │ │ ├── StringBuffer.js │ │ │ │ │ ├── SyntaxError.js │ │ │ │ │ ├── System.js │ │ │ │ │ ├── Throwable.js │ │ │ │ │ ├── TypeError.js │ │ │ │ │ ├── URIError.js │ │ │ │ │ ├── UnsupportedOperationException.js │ │ │ │ │ └── reflect │ │ │ │ │ │ ├── Constructor.js │ │ │ │ │ │ ├── Field.js │ │ │ │ │ │ ├── InvocationTargetException.js │ │ │ │ │ │ ├── Method.js │ │ │ │ │ │ └── Modifier.js │ │ │ │ │ ├── net │ │ │ │ │ ├── Http.js │ │ │ │ │ ├── HttpURLConnection.js │ │ │ │ │ ├── Rest.js │ │ │ │ │ ├── URLClassLoader.js │ │ │ │ │ └── URLConnection.js │ │ │ │ │ ├── test │ │ │ │ │ ├── Assert.js │ │ │ │ │ ├── AssertionError.js │ │ │ │ │ └── TestCase.js │ │ │ │ │ ├── text │ │ │ │ │ ├── DateFormat.js │ │ │ │ │ ├── DateFormatSymbols.js │ │ │ │ │ ├── FieldPosition.js │ │ │ │ │ ├── Format.js │ │ │ │ │ └── SimpleDateFormat.js │ │ │ │ │ └── util │ │ │ │ │ ├── ArrayList.js │ │ │ │ │ ├── Arrays.js │ │ │ │ │ ├── Calendar.js │ │ │ │ │ ├── Collection.js │ │ │ │ │ ├── Date.js │ │ │ │ │ ├── Entry.js │ │ │ │ │ ├── EntrySet.js │ │ │ │ │ ├── GregorianCalendar.js │ │ │ │ │ ├── HashIterator.js │ │ │ │ │ ├── HashMap.js │ │ │ │ │ ├── HashSet.js │ │ │ │ │ ├── Iterator.js │ │ │ │ │ ├── KeyIterator.js │ │ │ │ │ ├── KeySet.js │ │ │ │ │ ├── LinkIterator.js │ │ │ │ │ ├── List.js │ │ │ │ │ ├── Map.js │ │ │ │ │ ├── NoSuchElementException.js │ │ │ │ │ ├── Properties.js │ │ │ │ │ ├── Queue.js │ │ │ │ │ ├── Set.js │ │ │ │ │ ├── Stack.js │ │ │ │ │ ├── TreeMap.js │ │ │ │ │ ├── TreeSet.js │ │ │ │ │ ├── ValueIterator.js │ │ │ │ │ └── ValueList.js │ │ │ │ └── test │ │ │ │ ├── html │ │ │ │ └── index.html │ │ │ │ └── js │ │ │ │ └── js │ │ │ │ ├── lang │ │ │ │ ├── TestOOP.js │ │ │ │ ├── TestObject.js │ │ │ │ ├── TestStringBuffer.js │ │ │ │ └── reflect │ │ │ │ │ ├── TestClass.js │ │ │ │ │ ├── TestField.js │ │ │ │ │ └── TestMethod.js │ │ │ │ ├── model │ │ │ │ ├── Animal.js │ │ │ │ └── Dog.js │ │ │ │ ├── text │ │ │ │ └── TestDateFormat.js │ │ │ │ └── util │ │ │ │ ├── TestArrayList.js │ │ │ │ ├── TestCalendar.js │ │ │ │ ├── TestDate.js │ │ │ │ ├── TestGregorianCalendar.js │ │ │ │ ├── TestHashMap.js │ │ │ │ ├── TestHashSet.js │ │ │ │ ├── TestList.js │ │ │ │ └── TestMap.js │ │ ├── logo.ico │ │ ├── package.json │ │ ├── pom.json │ │ ├── rest_framework │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ └── glyphicons-halflings-regular.woff │ │ │ ├── img │ │ │ │ ├── glyphicons-halflings-white.png │ │ │ │ ├── glyphicons-halflings.png │ │ │ │ └── grid.png │ │ │ └── js │ │ │ │ ├── bootstrap.min.js │ │ │ │ ├── default.js │ │ │ │ ├── jquery-1.8.1-min.js │ │ │ │ └── prettify-min.js │ │ ├── rest_framework_swagger │ │ │ ├── images │ │ │ │ ├── logo_small.png │ │ │ │ ├── pet_store_api.png │ │ │ │ ├── throbber.gif │ │ │ │ └── wordnik_api.png │ │ │ ├── swagger-ui.js │ │ │ └── swagger-ui.min.js │ │ └── src │ │ │ └── main │ │ │ ├── css │ │ │ ├── animate.css │ │ │ ├── animate.less │ │ │ ├── beautifybox.css │ │ │ ├── beautifybox.less │ │ │ ├── bubbles.css │ │ │ ├── bubbles.less │ │ │ ├── bxslider.css │ │ │ ├── bxslider.less │ │ │ ├── components.css │ │ │ ├── components.less │ │ │ ├── contentflow.css │ │ │ ├── contentflow.less │ │ │ ├── countdown.css │ │ │ ├── countdown.less │ │ │ ├── cover.css │ │ │ ├── cover.less │ │ │ ├── easypie.css │ │ │ ├── easypie.less │ │ │ ├── flowstep.css │ │ │ ├── flowstep.less │ │ │ ├── histories.css │ │ │ ├── histories.less │ │ │ ├── index.css │ │ │ ├── index.less │ │ │ ├── notification.css │ │ │ ├── notification.less │ │ │ ├── plumb.css │ │ │ ├── plumb.less │ │ │ ├── sidebar.css │ │ │ ├── sidebar.less │ │ │ ├── tars.css │ │ │ └── tars.less │ │ │ ├── images │ │ │ ├── 1x1_0.5_black.png │ │ │ ├── 404-lg.png │ │ │ ├── 404-md.png │ │ │ ├── 404-sm.png │ │ │ ├── 404-xs.png │ │ │ ├── arrow-bottom-left.png │ │ │ ├── arrow-bottom-left2.png │ │ │ ├── arrow-bottom-right.png │ │ │ ├── arrow-bottom-right2.png │ │ │ ├── arrow-top-left.png │ │ │ ├── arrow-top-left2.png │ │ │ ├── arrow-top-right.png │ │ │ ├── arrow-top-right2.png │ │ │ ├── bg_noise.png │ │ │ ├── bg_stitch.png │ │ │ ├── blank.gif │ │ │ ├── body_bg.gif │ │ │ ├── bxslider │ │ │ │ ├── bx_loader.gif │ │ │ │ ├── clog-36.png │ │ │ │ └── controls.png │ │ │ ├── chart │ │ │ │ └── circlepin-30.png │ │ │ ├── ctrl-up-down.png │ │ │ ├── goback.png │ │ │ ├── loader.gif │ │ │ ├── loading.gif │ │ │ ├── lockscreen.png │ │ │ ├── logo.ico │ │ │ ├── logo.png │ │ │ ├── postmark.png │ │ │ ├── resource │ │ │ │ ├── lockscreen.png │ │ │ │ └── uc_user.png │ │ │ ├── rm-36.png │ │ │ ├── scrollbar_white.png │ │ │ ├── sleep-lg.png │ │ │ ├── slider_white.png │ │ │ ├── tars.png │ │ │ ├── uc_user.png │ │ │ ├── upload │ │ │ │ └── user │ │ │ │ │ ├── photo-user.png │ │ │ │ │ └── zhuoluo.jpg │ │ │ └── xmon-36.png │ │ │ ├── js │ │ │ └── com │ │ │ │ ├── ctrip │ │ │ │ └── tars │ │ │ │ │ ├── Portal.js │ │ │ │ │ ├── app │ │ │ │ │ └── App.js │ │ │ │ │ ├── apps │ │ │ │ │ ├── Apps.js │ │ │ │ │ ├── Service.js │ │ │ │ │ └── multi │ │ │ │ │ │ ├── Apps.js │ │ │ │ │ │ └── filter │ │ │ │ │ │ └── MonitorStatus.js │ │ │ │ │ ├── base │ │ │ │ │ ├── DefaultService.js │ │ │ │ │ ├── PaginationService.js │ │ │ │ │ ├── SegmentService.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── batches │ │ │ │ │ └── Batches.js │ │ │ │ │ ├── component │ │ │ │ │ ├── Command.js │ │ │ │ │ ├── Dragmove.js │ │ │ │ │ ├── IAjax.js │ │ │ │ │ ├── ICheckbox.js │ │ │ │ │ ├── IContentFlow.js │ │ │ │ │ ├── IFlow.js │ │ │ │ │ ├── IFlow2.js │ │ │ │ │ ├── IForm.js │ │ │ │ │ ├── IPlumb.js │ │ │ │ │ ├── IScroll.js │ │ │ │ │ ├── ISearch.js │ │ │ │ │ ├── ISlider.js │ │ │ │ │ ├── angular │ │ │ │ │ │ ├── accordion │ │ │ │ │ │ │ └── Accordion.js │ │ │ │ │ │ ├── action │ │ │ │ │ │ │ └── Action.js │ │ │ │ │ │ ├── bubble │ │ │ │ │ │ │ └── Bubble.js │ │ │ │ │ │ ├── contentflow │ │ │ │ │ │ │ └── ContentFlow.js │ │ │ │ │ │ ├── countdown │ │ │ │ │ │ │ └── Countdown.js │ │ │ │ │ │ ├── cover │ │ │ │ │ │ │ └── Cover.js │ │ │ │ │ │ ├── d3 │ │ │ │ │ │ │ └── Tree.js │ │ │ │ │ │ ├── expander │ │ │ │ │ │ │ └── Expander.js │ │ │ │ │ │ ├── flowstep │ │ │ │ │ │ │ └── Flowstep.js │ │ │ │ │ │ ├── flp │ │ │ │ │ │ │ └── Flp.js │ │ │ │ │ │ ├── iButton │ │ │ │ │ │ │ └── iButton.js │ │ │ │ │ │ ├── ink │ │ │ │ │ │ │ └── Ink.js │ │ │ │ │ │ ├── layout │ │ │ │ │ │ │ └── Concern.js │ │ │ │ │ │ ├── notification │ │ │ │ │ │ │ └── Notification.js │ │ │ │ │ │ ├── pagination │ │ │ │ │ │ │ └── Pagination.js │ │ │ │ │ │ ├── percent │ │ │ │ │ │ │ ├── Bar.js │ │ │ │ │ │ │ ├── Easypie.js │ │ │ │ │ │ │ └── Pie.js │ │ │ │ │ │ ├── popout │ │ │ │ │ │ │ └── Popouts.js │ │ │ │ │ │ ├── postmark │ │ │ │ │ │ │ └── Postmark.js │ │ │ │ │ │ ├── sidebar │ │ │ │ │ │ │ └── Sidebar.js │ │ │ │ │ │ ├── slider │ │ │ │ │ │ │ └── IonRange.js │ │ │ │ │ │ ├── tabpanel │ │ │ │ │ │ │ └── Tabpanel.js │ │ │ │ │ │ ├── tooltip │ │ │ │ │ │ │ └── Tooltip.js │ │ │ │ │ │ └── tween │ │ │ │ │ │ │ ├── Menu.js │ │ │ │ │ │ │ ├── Share.js │ │ │ │ │ │ │ └── Show.js │ │ │ │ │ └── chart │ │ │ │ │ │ ├── Bar.js │ │ │ │ │ │ ├── Easypie.js │ │ │ │ │ │ ├── Highcharts.js │ │ │ │ │ │ ├── Pie.js │ │ │ │ │ │ └── Stock.js │ │ │ │ │ ├── config │ │ │ │ │ ├── Config.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── console │ │ │ │ │ ├── Console.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── controller │ │ │ │ │ ├── Dispatcher.js │ │ │ │ │ ├── Index.js │ │ │ │ │ └── Root.js │ │ │ │ │ ├── deployments │ │ │ │ │ ├── Parallel.js │ │ │ │ │ ├── Serial.js │ │ │ │ │ ├── Single.js │ │ │ │ │ ├── Tabs.js │ │ │ │ │ └── tabs │ │ │ │ │ │ └── Tabpanel.js │ │ │ │ │ ├── events │ │ │ │ │ └── Events.js │ │ │ │ │ ├── exceptions │ │ │ │ │ └── Exceptions.js │ │ │ │ │ ├── filter │ │ │ │ │ └── Filter.js │ │ │ │ │ ├── group │ │ │ │ │ ├── Command.js │ │ │ │ │ ├── CommandGroup.js │ │ │ │ │ ├── Contribution.js │ │ │ │ │ ├── Group.js │ │ │ │ │ ├── Service.js │ │ │ │ │ ├── rollback │ │ │ │ │ │ ├── Cancel.js │ │ │ │ │ │ ├── CommandGroup.js │ │ │ │ │ │ ├── Confirm.js │ │ │ │ │ │ ├── Controller.js │ │ │ │ │ │ └── Service.js │ │ │ │ │ └── rollout │ │ │ │ │ │ ├── Cancel.js │ │ │ │ │ │ ├── CommandGroup.js │ │ │ │ │ │ ├── Confirm.js │ │ │ │ │ │ ├── Controller.js │ │ │ │ │ │ ├── Next.js │ │ │ │ │ │ ├── Previous.js │ │ │ │ │ │ └── Settings.js │ │ │ │ │ ├── groups │ │ │ │ │ ├── Groups.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── header │ │ │ │ │ └── Header.js │ │ │ │ │ ├── histories │ │ │ │ │ ├── Histories.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── model │ │ │ │ │ ├── Application.js │ │ │ │ │ ├── DeploymentTargetSteps.js │ │ │ │ │ ├── Flowstep.js │ │ │ │ │ ├── Group.js │ │ │ │ │ ├── Notification.js │ │ │ │ │ ├── Runtime.js │ │ │ │ │ └── User.js │ │ │ │ │ ├── navigator │ │ │ │ │ └── Navigator.js │ │ │ │ │ ├── packages │ │ │ │ │ ├── Packages.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── plumb │ │ │ │ │ └── Plumb.js │ │ │ │ │ ├── progress │ │ │ │ │ ├── Components.js │ │ │ │ │ ├── Deploying.js │ │ │ │ │ ├── Progress.js │ │ │ │ │ └── Working.js │ │ │ │ │ ├── security │ │ │ │ │ └── Security.js │ │ │ │ │ ├── servers │ │ │ │ │ ├── Servers.js │ │ │ │ │ └── Service.js │ │ │ │ │ ├── subscriptions │ │ │ │ │ └── Subscription.js │ │ │ │ │ ├── util │ │ │ │ │ ├── Angular.js │ │ │ │ │ ├── Chart.js │ │ │ │ │ ├── Common.js │ │ │ │ │ ├── Csrf.js │ │ │ │ │ ├── Fridge.js │ │ │ │ │ ├── Id.js │ │ │ │ │ ├── Jquery.js │ │ │ │ │ ├── LocalStorage.js │ │ │ │ │ ├── SegmentTable.js │ │ │ │ │ ├── Slot.js │ │ │ │ │ └── Watch.js │ │ │ │ │ ├── welcome │ │ │ │ │ └── Welcome.js │ │ │ │ │ └── xmon │ │ │ │ │ └── Xmon.js │ │ │ │ └── highstock │ │ │ │ ├── DraggablePoints.js │ │ │ │ └── Theme.js │ │ │ ├── skin │ │ │ ├── default │ │ │ │ └── css │ │ │ │ │ ├── skin.css │ │ │ │ │ └── skin.less │ │ │ ├── fat │ │ │ │ └── css │ │ │ │ │ ├── skin.css │ │ │ │ │ └── skin.less │ │ │ ├── skins.less │ │ │ ├── test │ │ │ │ └── css │ │ │ │ │ ├── skin.css │ │ │ │ │ └── skin.less │ │ │ └── uat │ │ │ │ └── css │ │ │ │ ├── skin.css │ │ │ │ └── skin.less │ │ │ └── template │ │ │ ├── 404.html │ │ │ ├── apps.html │ │ │ ├── cis.html │ │ │ ├── deployment.html │ │ │ ├── deployment │ │ │ └── tabpanel.html │ │ │ ├── dialog │ │ │ ├── batches.html │ │ │ ├── rollback.html │ │ │ ├── rollback │ │ │ │ └── preview.html │ │ │ ├── rollout.html │ │ │ └── rollout │ │ │ │ ├── 1.html │ │ │ │ ├── 2.html │ │ │ │ └── 3.html │ │ │ ├── group.html │ │ │ ├── groups.html │ │ │ ├── index.html │ │ │ ├── login.html │ │ │ ├── parallel.html │ │ │ ├── pools.html │ │ │ ├── serial.html │ │ │ └── single.html │ ├── templates │ │ ├── OnService.html │ │ ├── admin │ │ │ ├── 404.html │ │ │ ├── 500.html │ │ │ ├── actions.html │ │ │ ├── app_index.html │ │ │ ├── auth │ │ │ │ └── user │ │ │ │ │ ├── add_form.html │ │ │ │ │ └── change_password.html │ │ │ ├── base.html │ │ │ ├── base_site.html │ │ │ ├── change_form.html │ │ │ ├── change_list.html │ │ │ ├── change_list_results.html │ │ │ ├── date_hierarchy.html │ │ │ ├── delete_confirmation.html │ │ │ ├── delete_selected_confirmation.html │ │ │ ├── edit_inline │ │ │ │ ├── stacked.html │ │ │ │ └── tabular.html │ │ │ ├── filter.html │ │ │ ├── includes │ │ │ │ └── fieldset.html │ │ │ ├── index.html │ │ │ ├── invalid_setup.html │ │ │ ├── login.html │ │ │ ├── object_history.html │ │ │ ├── pagination.html │ │ │ ├── popup_response.html │ │ │ ├── prepopulated_fields_js.html │ │ │ ├── search_form.html │ │ │ └── submit_line.html │ │ ├── constance_change_list.html │ │ ├── index.html │ │ ├── settings.html │ │ └── surface_login.html │ ├── urls.py │ └── views.py ├── urls.py ├── utils.py └── wsgi.py └── tools ├── celeryd ├── celeryd.conf ├── celeryd.conf.j2 ├── deploy.sh ├── maintain.sh ├── restart.sh ├── tarsd └── tarsd.ini /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | ENV PYTHONUNBUFFERED 1 3 | ADD requirements /requirements 4 | RUN pip install -r requirements/local.txt --trusted-host pypi.douban.com 5 | RUN mkdir /code 6 | WORKDIR /code 7 | ADD ./ /code/ 8 | 9 | -------------------------------------------------------------------------------- /Dockerfile-demo: -------------------------------------------------------------------------------- 1 | FROM python:2.7 2 | ENV PYTHONUNBUFFERED 1 3 | ADD requirements /requirements 4 | 5 | RUN pip install -r /requirements/local.txt --trusted-host pypi.douban.com 6 | 7 | RUN mkdir /code 8 | WORKDIR /code 9 | 10 | COPY demo/files/shared/ssh/id_rsa.pub /root/.ssh/id_rsa.pub 11 | COPY demo/files/shared/ssh/id_rsa /root/.ssh/id_rsa 12 | COPY demo/files/shared/ssh/authorized_keys /root/.ssh/authorized_keys 13 | 14 | RUN chmod 600 /root/.ssh/authorized_keys 15 | RUN chmod 600 /root/.ssh/id_rsa 16 | 17 | RUN chown -R root:root /root/.ssh 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docker bootstrap 2 | 3 | Requirements 4 | 5 | - docker and docker-compose 6 | - GNU make 7 | 8 | Preperations 9 | 10 | ``` bash 11 | cp tars/settings/local.py.example tars/settings/local.py 12 | ``` 13 | 14 | Just type 15 | 16 | ``` bash 17 | make docker_bootstrap 18 | ``` 19 | 20 | Then, please visit http://localhost:8000 to access Tars 21 | 22 | # Frontend 23 | 24 | Build frontend 25 | 26 | ```bash 27 | make frontend 28 | ``` 29 | 30 | Build frontend using docker, please ensure container exit code is 0 31 | 32 | ```bash 33 | make frontend_docker 34 | ``` 35 | 36 | If failed to install bower components, please try branch `demo/static_embedded` 37 | 38 | # Docker demo 39 | 40 | ``` bash 41 | ./demo/bootstrap.sh 42 | ``` 43 | 44 | Demo admin account: 45 | 46 | * username: admin 47 | * password: nomoresecrete 48 | -------------------------------------------------------------------------------- /ansible_playbook/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/ansible_playbook/__init__.py -------------------------------------------------------------------------------- /ansible_playbook/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deploy for tomcat app 3 | hosts: all 4 | remote_user: "{{ login_user }}" 5 | sudo: True 6 | vars: 7 | # ansistrano_deploy_from: "/Users/cy/vagrant/tarstest/tars" 8 | ansistrano_release_version: "{{ release_version }}" 9 | ansistrano_deploy_via: "download_unarchive" 10 | ansistrano_get_url: "{{ package_url }}" 11 | ansistrano_allow_anonymous_stats: False 12 | ansistrano_after_symlink_tasks_file: "{{ playbook_dir }}/shared/after-symlink.yml" 13 | roles: 14 | - { role: carlosbuenosvinos.ansistrano-deploy } 15 | -------------------------------------------------------------------------------- /ansible_playbook/hosts: -------------------------------------------------------------------------------- 1 | [all:vars] 2 | env=matrix 3 | login_user=root 4 | gulp_target_env=matrix 5 | 6 | 7 | [webservers] 8 | 10.18.5.26 9 | -------------------------------------------------------------------------------- /ansible_playbook/requirements.yml: -------------------------------------------------------------------------------- 1 | # ansible-galaxy install -r requirements.yml 2 | 3 | # carlosbuenosvinos.ansistrano-deploy 4 | - src: carlosbuenosvinos.ansistrano-deploy -------------------------------------------------------------------------------- /ansible_playbook/roles/skip/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Path where the code must be deployed to 3 | ansistrano_deploy_to: "/var/www/my-app" 4 | 5 | # Folder name for the releases 6 | ansistrano_version_dir: "releases" 7 | 8 | # Softlink name for the current release 9 | ansistrano_current_dir: "current" 10 | -------------------------------------------------------------------------------- /ansible_playbook/roles/skip/tasks/main.yml: -------------------------------------------------------------------------------- 1 | # ansible-playbook skip.yml -i hosts -e release_version=222 -e package_url="http://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/sample.war" -e ansistrano_after_symlink_tasks_file="{{ playbook_dir }}/shared/after-symlink.yml" 2 | - name: ANSISTRANO | Check if current 3 | shell: readlink {{ ansistrano_deploy_to }}/{{ ansistrano_current_dir }} | grep -e '/{{ release_version }}$' 4 | -------------------------------------------------------------------------------- /ansible_playbook/shared/after-symlink.yml: -------------------------------------------------------------------------------- 1 | # Performs symlink exchange 2 | - name: ANSISTRANO | Ensure tomcat webapps ROOT link 3 | file: 4 | state: link 5 | path: "/usr/share/tomcat/webapps/ROOT" 6 | src: "{{ ansistrano_deploy_to }}/{{ ansistrano_current_dir }}" 7 | 8 | # - name: ANSISTRANO | Ensure tomcat restarted 9 | # service: name=tomcat state=restarted 10 | 11 | - name: Manage the state of a program or group of programs running via supervisord 12 | supervisorctl: name=tomcat state=restarted 13 | -------------------------------------------------------------------------------- /ansible_playbook/skip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Check can skip deploy for tomcat app 3 | hosts: all 4 | remote_user: "{{ login_user }}" 5 | sudo: True 6 | vars: 7 | # ansistrano_deploy_from: "/Users/cy/vagrant/tarstest/tars" 8 | ansistrano_release_version: "{{ release_version }}" 9 | ansistrano_deploy_via: "download" 10 | ansistrano_get_url: "{{ package_url }}" 11 | ansistrano_allow_anonymous_stats: False 12 | roles: 13 | - { role: skip } 14 | -------------------------------------------------------------------------------- /ansible_playbook/version.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/ansible_playbook/version.yml -------------------------------------------------------------------------------- /demo/Dockerfile-Tomcat: -------------------------------------------------------------------------------- 1 | FROM centos:7 2 | 3 | COPY files/tomcat/etc/yum.repos.d/CentOS-Epel.repo /etc/yum.repos.d/CentOS-Epel.repo 4 | 5 | # Install software 6 | RUN yum install -y sudo net-tools openssh-server openssh-clients supervisor tomcat unzip 7 | 8 | # Manage ssh key 9 | RUN mkdir -p /root/.ssh 10 | 11 | COPY files/shared/ssh/id_rsa.pub /root/.ssh/id_rsa.pub 12 | COPY files/shared/ssh/id_rsa /root/.ssh/id_rsa 13 | COPY files/shared/ssh/authorized_keys /root/.ssh/authorized_keys 14 | COPY files/tomcat/etc/ssh/ssh_host_rsa_key /etc/ssh/ssh_host_rsa_key 15 | COPY files/tomcat/etc/ssh/ssh_host_rsa_key.pub /etc/ssh/ssh_host_rsa_key.pub 16 | 17 | RUN chmod 600 /root/.ssh/authorized_keys 18 | RUN chmod 600 /root/.ssh/id_rsa 19 | RUN chmod 600 /etc/ssh/ssh_host_rsa_key 20 | 21 | RUN chown -R root:root /root/.ssh 22 | RUN chown -R root:root /etc/ssh/ 23 | 24 | # Clean all 25 | RUN yum clean all 26 | 27 | CMD [ "supervisord", "-n" ] 28 | -------------------------------------------------------------------------------- /demo/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd $(dirname $0) 6 | 7 | ./init.sh 8 | 9 | docker-compose -f ../docker-compose-frontend.yml up 10 | 11 | docker-compose up -d db 12 | 13 | echo Ensure db instance is started... 14 | sleep 20s 15 | 16 | docker-compose build && docker-compose up 17 | 18 | echo "Please visit http://localhost:8000 to access Tars, Enjoy it :)" 19 | -------------------------------------------------------------------------------- /demo/clean_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd $(dirname $0) 3 | 4 | docker-compose stop 5 | docker-compose down --rmi local -v 6 | 7 | cd - 8 | -------------------------------------------------------------------------------- /demo/docker-compose-common.yml: -------------------------------------------------------------------------------- 1 | server: 2 | build: . 3 | dockerfile: Dockerfile-Tomcat 4 | volumes: 5 | - ./files/tomcat/etc/supervisord.d/:/etc/supervisord.d 6 | 7 | code: 8 | build: .. 9 | dockerfile: Dockerfile-demo 10 | volumes: 11 | - ../:/code 12 | - ./files/code/etc/ssh/ssh_config:/etc/ssh/ssh_config 13 | - ./files/code/etc/ansible/roles:/etc/ansible/roles 14 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | ### Vagrant template 4 | .vagrant/ 5 | 6 | ### JetBrains template 7 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 8 | 9 | *.iml 10 | 11 | ## Directory-based project format: 12 | .idea/ 13 | # if you remove the above rule, at least ignore the following: 14 | 15 | # User-specific stuff: 16 | # .idea/workspace.xml 17 | # .idea/tasks.xml 18 | # .idea/dictionaries 19 | 20 | # Sensitive or high-churn files: 21 | # .idea/dataSources.ids 22 | # .idea/dataSources.xml 23 | # .idea/sqlDataSources.xml 24 | # .idea/dynamic.xml 25 | # .idea/uiDesigner.xml 26 | 27 | # Gradle: 28 | # .idea/gradle.xml 29 | # .idea/libraries 30 | 31 | # Mongo Explorer plugin: 32 | # .idea/mongoSettings.xml 33 | 34 | ## File-based project format: 35 | *.ipr 36 | *.iws 37 | 38 | ## Plugin-specific files: 39 | 40 | # IntelliJ 41 | /out/ 42 | 43 | # mpeltonen/sbt-idea plugin 44 | .idea_modules/ 45 | 46 | # JIRA plugin 47 | atlassian-ide-plugin.xml 48 | 49 | # Crashlytics plugin (for Android Studio and IntelliJ) 50 | com_crashlytics_export_strings.xml 51 | crashlytics.properties 52 | crashlytics-build.properties 53 | 54 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: required 3 | dist: trusty 4 | 5 | matrix: 6 | include: 7 | - env: ANSIBLE_VERSION=1.8.4 8 | - env: ANSIBLE_VERSION=1.9.5 9 | - env: ANSIBLE_VERSION=2.1.0 10 | 11 | before_install: 12 | - sudo apt-get -y install software-properties-common 13 | - sudo apt-get -y install python-pip 14 | - sudo pip install ansible==$ANSIBLE_VERSION 15 | - ansible --version 16 | 17 | script: 18 | - echo localhost > inventory 19 | - ansible-playbook -i inventory --connection=local --sudo -v test/test.yml 20 | 21 | notifications: 22 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2016 Carlos Buenosvinos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/TESTING.md: -------------------------------------------------------------------------------- 1 | Testing locally with Ansible 2.x 2 | ================================ 3 | 4 | git clone git@github.com:ansistrano/deploy.git 5 | cd deploy 6 | vagrant up 7 | cd example/my-playbook 8 | ansible-playbook deploy.yml -i hosts -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/Vagrantfile: -------------------------------------------------------------------------------- 1 | Vagrant.configure("2") do |config| 2 | config.vm.define 'web01' do |config| 3 | config.vm.box = 'ubuntu/trusty64' 4 | config.vm.hostname = 'web01' 5 | config.vm.synced_folder '.', '/vagrant', disabled: true 6 | end 7 | 8 | config.vm.define 'web02' do |config| 9 | config.vm.box = 'ubuntu/trusty64' 10 | config.vm.hostname = 'web02' 11 | config.vm.synced_folder '.', '/vagrant', disabled: true 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | roles_path = ../ -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/docs/ansistrano-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/docs/ansistrano-flow.png -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/docs/figure.md: -------------------------------------------------------------------------------- 1 | http://yuml.me/edit/5473b608 2 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/example/my-app/index.html: -------------------------------------------------------------------------------- 1 | This is the main file of the project, I know it's not too much, but it will :) -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/example/my-playbook/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking=False -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/example/my-playbook/deploy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deploy example app to my-server.com 3 | hosts: all 4 | vars: 5 | ansistrano_deploy_from: "{{ playbook_dir }}/../my-app" 6 | ansistrano_deploy_to: "/tmp/my-app.com" 7 | ansistrano_keep_releases: 3 8 | # There seems to be an issue with rsync in vagrant 9 | ansistrano_deploy_via: copy 10 | roles: 11 | - { role: carlosbuenosvinos.ansistrano-deploy } -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/example/my-playbook/hosts: -------------------------------------------------------------------------------- 1 | web01 ansible_user=vagrant ansible_port=2222 ansible_host=127.0.0.1 ansible_ssh_private_key_file=../../.vagrant/machines/web01/virtualbox/private_key 2 | web02 ansible_user=vagrant ansible_port=2200 ansible_host=127.0.0.1 ansible_ssh_private_key_file=../../.vagrant/machines/web02/virtualbox/private_key -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/example/my-playbook/rollback.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Rollback example app to my-server.com 3 | hosts: all 4 | vars: 5 | ansistrano_deploy_to: "/tmp/my-app.com" 6 | roles: 7 | - { role: carlosbuenosvinos.ansistrano-rollback } -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/meta/.galaxy_install_info: -------------------------------------------------------------------------------- 1 | {install_date: 'Thu Nov 3 10:37:28 2016', version: 1.10.1} 2 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | author: ansistrano 4 | description: Ansible role to deploy scripting applications like PHP, Python, Ruby, etc. in a Capistrano style 5 | company: Ansistrano 6 | license: MIT 7 | min_ansible_version: 1.8 8 | platforms: 9 | - name: EL 10 | versions: 11 | - all 12 | - name: GenericUNIX 13 | versions: 14 | - all 15 | - name: Fedora 16 | versions: 17 | - all 18 | - name: opensuse 19 | versions: 20 | - all 21 | - name: Amazon 22 | versions: 23 | - all 24 | - name: GenericBSD 25 | versions: 26 | - all 27 | - name: FreeBSD 28 | versions: 29 | - all 30 | - name: Ubuntu 31 | versions: 32 | - all 33 | - name: SLES 34 | versions: 35 | - all 36 | - name: GenericLinux 37 | versions: 38 | - all 39 | - name: Debian 40 | versions: 41 | - all 42 | categories: 43 | - cloud 44 | - web 45 | dependencies: [] 46 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/anon-stats.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Sends anonymous stats if the user is ok with it 3 | - name: ANSISTRANO | Send anonymous stats 4 | uri: 5 | url: http://ansistrano.com/deploy 6 | method: POST 7 | timeout: 5 8 | when: ansistrano_allow_anonymous_stats 9 | run_once: true 10 | ignore_errors: yes 11 | delegate_to: 127.0.0.1 12 | sudo: false 13 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Clean up releases 3 | - name: ANSISTRANO | Clean up releases 4 | shell: ls -1dt {{ ansistrano_releases_path.stdout }}/* | tail -n +{{ ansistrano_keep_releases | int + 1 }} | xargs rm -rf 5 | when: ansistrano_keep_releases > 0 6 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/empty.yml: -------------------------------------------------------------------------------- 1 | # This file is intentionally left empty and it is used in those Capistrano flow steps 2 | # where you don't need to execute any custom tasks -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Setup folders 3 | - name: ANSISTRANO | Ensure deployment base path exists 4 | file: 5 | state: directory 6 | path: "{{ ansistrano_deploy_to }}" 7 | 8 | - name: ANSISTRANO | Set releases path 9 | command: echo "{{ ansistrano_deploy_to }}/{{ ansistrano_version_dir }}" 10 | register: ansistrano_releases_path 11 | 12 | - name: ANSISTRANO | Ensure releases folder exists 13 | file: 14 | state: directory 15 | path: "{{ ansistrano_releases_path.stdout }}" 16 | 17 | - name: ANSISTRANO | Set shared path 18 | command: echo "{{ ansistrano_deploy_to }}/shared" 19 | register: ansistrano_shared_path 20 | 21 | - name: ANSISTRANO | Ensure shared elements folder exists 22 | file: 23 | state: directory 24 | path: "{{ ansistrano_shared_path.stdout }}" 25 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/symlink.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Migration check from rsync deployment 4 | - stat: 5 | path: "{{ ansistrano_deploy_to }}/{{ ansistrano_current_dir }}" 6 | register: stat_current_dir 7 | 8 | - name: ANSISTRANO | Remove current folder if it's a directory 9 | file: 10 | state: absent 11 | path: "{{ ansistrano_deploy_to }}/{{ ansistrano_current_dir }}" 12 | when: stat_current_dir.stat.isdir is defined and stat_current_dir.stat.isdir 13 | 14 | # Performs symlink exchange 15 | - name: ANSISTRANO | Change softlink to new release 16 | file: 17 | state: link 18 | path: "{{ ansistrano_deploy_to }}/{{ ansistrano_current_dir }}" 19 | src: "./{{ ansistrano_version_dir }}/{{ ansistrano_release_version }}" 20 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Update code deployment step 3 | - name: ANSISTRANO | Get release version 4 | set_fact: 5 | ansistrano_release_version: "{{ lookup('pipe', 'date -u +%Y%m%d%H%M%SZ') }}" 6 | run_once: true 7 | when: ansistrano_release_version is not defined 8 | delegate_to: 127.0.0.1 9 | 10 | - name: ANSISTRANO | Get release path 11 | command: echo "{{ ansistrano_releases_path.stdout }}/{{ ansistrano_release_version }}" 12 | register: ansistrano_release_path 13 | 14 | - include: "update-code/{{ ansistrano_deploy_via | default('rsync') }}.yml" 15 | 16 | - name: ANSISTRANO | Copy release version into REVISION file 17 | copy: 18 | content: "{{ ansistrano_release_version }}" 19 | dest: "{{ ansistrano_release_path.stdout }}/REVISION" 20 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/copy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | SCP | Create release folder 3 | file: 4 | state: directory 5 | path: "{{ ansistrano_release_path.stdout }}" 6 | 7 | - name: ANSISTRANO | SCP | Deploy existing code to remote servers 8 | copy: 9 | src: "{{ ansistrano_deploy_from }}" 10 | dest: "{{ ansistrano_release_path.stdout }}" 11 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/copy_unarchive.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: copy.yml 3 | 4 | - name: ANSISTRANO | copy_unarchive | Set archived file 5 | set_fact: 6 | ansistrano_archived_file: "{{ ansistrano_release_path.stdout }}/{{ ansistrano_deploy_from | basename }}" 7 | 8 | - include: unarchive.yml 9 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/download.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | download | Create release folder 3 | file: 4 | state: directory 5 | path: "{{ ansistrano_release_path.stdout }}" 6 | 7 | - name: ANSISTRANO | download | Download artifact 8 | get_url: 9 | url: "{{ ansistrano_get_url }}" 10 | dest: "{{ ansistrano_release_path.stdout }}/{{ ansistrano_get_url | basename }}" 11 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/download_unarchive.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: download.yml 3 | 4 | - name: ANSISTRANO | download_unarchive | Set archived file 5 | set_fact: 6 | ansistrano_archived_file: "{{ ansistrano_release_path.stdout }}/{{ ansistrano_get_url | basename }}" 7 | 8 | - include: unarchive.yml 9 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/rsync.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | RSYNC | Get shared path (in rsync case) 3 | command: echo "{{ ansistrano_shared_path.stdout }}/.shared-copy" 4 | register: ansistrano_shared_rsync_copy_path 5 | 6 | - name: ANSISTRANO | RSYNC | Rsync application files to remote shared copy 7 | synchronize: 8 | src: "{{ ansistrano_deploy_from }}" 9 | dest: "{{ ansistrano_shared_rsync_copy_path.stdout }}" 10 | set_remote_user: "{{ ansistrano_rsync_set_remote_user }}" 11 | recursive: yes 12 | delete: yes 13 | archive: yes 14 | compress: yes 15 | rsync_opts: "{{ ansistrano_rsync_extra_params }}" 16 | 17 | - name: ANSISTRANO | RSYNC | Deploy existing code to servers 18 | command: cp -a {{ ansistrano_shared_rsync_copy_path.stdout }} {{ ansistrano_release_path.stdout }} 19 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/s3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | S3 | Create release folder 3 | file: 4 | state: directory 5 | path: "{{ ansistrano_release_path.stdout }}" 6 | 7 | - name: ANSISTRANO | S3 | Get object from S3 8 | s3: 9 | bucket: "{{ ansistrano_s3_bucket }}" 10 | object: "{{ ansistrano_s3_object }}" 11 | dest: "{{ ansistrano_release_path.stdout }}/{{ ansistrano_s3_object | basename }}" 12 | mode: get 13 | region: "{{ ansistrano_s3_region }}" 14 | aws_access_key: "{{ ansistrano_s3_aws_access_key | default(omit) }}" 15 | aws_secret_key: "{{ ansistrano_s3_aws_secret_key | default(omit) }}" 16 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/s3_unarchive.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - include: s3.yml 3 | 4 | - name: ANSISTRANO | s3_unarchive | Set archived file 5 | set_fact: 6 | ansistrano_archived_file: "{{ ansistrano_release_path.stdout }}/{{ ansistrano_s3_object | basename }}" 7 | 8 | - include: unarchive.yml -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/tasks/update-code/unarchive.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | Unarchive | Unarchive source 3 | unarchive: 4 | copy: no 5 | src: "{{ ansistrano_archived_file }}" 6 | dest: "{{ ansistrano_release_path.stdout }}" 7 | 8 | - name: ANSISTRANO | Unarchive | Delete archived file 9 | file: 10 | path: "{{ ansistrano_archived_file }}" 11 | state: absent -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/test/tasks/create-internal-paths.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # We cannot create the symlinks unless these subfolders exist in the destination release folder 3 | - name: ANSISTRANO | Ensure internal path foo exists 4 | file: 5 | state: directory 6 | path: "{{ ansistrano_release_path.stdout }}/foo" 7 | 8 | - name: ANSISTRANO | Ensure internal path xxx/yyy exists 9 | file: 10 | state: directory 11 | path: "{{ ansistrano_release_path.stdout }}/xxx/yyy" 12 | 13 | - name: ANSISTRANO | Ensure internal path files exists 14 | file: 15 | state: directory 16 | path: "{{ ansistrano_release_path.stdout }}/files" 17 | -------------------------------------------------------------------------------- /demo/files/code/etc/ansible/roles/carlosbuenosvinos.ansistrano-deploy/test/tasks/create-shared-paths.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: ANSISTRANO | Ensure shared path 1 exists 3 | file: 4 | state: directory 5 | path: "{{ ansistrano_deploy_to }}/shared/blah" 6 | 7 | - name: ANSISTRANO | Ensure shared path 2 exists 8 | file: 9 | state: directory 10 | path: "{{ ansistrano_deploy_to }}/shared/foo/bar" 11 | 12 | - name: ANSISTRANO | Ensure shared path 3 exists 13 | file: 14 | state: directory 15 | path: "{{ ansistrano_deploy_to }}/shared/xxx/yyy/zzz" 16 | 17 | - name: ANSISTRANO | Ensure shared file 1 exists 18 | file: 19 | state: touch 20 | path: "{{ ansistrano_deploy_to }}/shared/test.txt" 21 | 22 | - name: ANSISTRANO | Ensure shared files folder exists 23 | file: 24 | state: directory 25 | path: "{{ ansistrano_deploy_to }}/shared/files" 26 | 27 | - name: ANSISTRANO | Ensure shared file 2 exists 28 | file: 29 | state: touch 30 | path: "{{ ansistrano_deploy_to }}/shared/files/test.txt" 31 | -------------------------------------------------------------------------------- /demo/files/code/etc/ssh/ssh_config: -------------------------------------------------------------------------------- 1 | SendEnv LANG LC_* 2 | HashKnownHosts yes 3 | GSSAPIAuthentication yes 4 | GSSAPIDelegateCredentials no 5 | StrictHostKeyChecking no 6 | -------------------------------------------------------------------------------- /demo/files/shared/ssh/authorized_keys: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDer3R8g1Fz18k7qVCY7wdwkmjATak/MaEjVErVoMTcmmyVgz9LxgviEhZdALm98Ru603VGvxJSR2zl7B4ZP7GA9S66dv6T/OU9v7RWZOcrjcYpGu6NJaY8NWDskJx3MsO50iiLdIy8sVLYbWGL2Ca1qqOpa/nCPRaGlwLGsS5SLrQAVDoEvivvo8FnWf1A8M/uatEtIA8J8nvwirVHSp3eIt9ZDfsu0+153o7mV6VzcqTTgIoCj+C3CK8tw9+H7s0zT96Wt/ph2wy16wAfoQCFi0nKwoEUL71jF6uggHD+0Zn7rC54I/9ovgHJVR0iiCnYUH75ZzDqX52pu4Tdh1b docker-demo 2 | -------------------------------------------------------------------------------- /demo/files/shared/ssh/id_rsa.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDer3R8g1Fz18k7qVCY7wdwkmjATak/MaEjVErVoMTcmmyVgz9LxgviEhZdALm98Ru603VGvxJSR2zl7B4ZP7GA9S66dv6T/OU9v7RWZOcrjcYpGu6NJaY8NWDskJx3MsO50iiLdIy8sVLYbWGL2Ca1qqOpa/nCPRaGlwLGsS5SLrQAVDoEvivvo8FnWf1A8M/uatEtIA8J8nvwirVHSp3eIt9ZDfsu0+153o7mV6VzcqTTgIoCj+C3CK8tw9+H7s0zT96Wt/ph2wy16wAfoQCFi0nKwoEUL71jF6uggHD+0Zn7rC54I/9ovgHJVR0iiCnYUH75ZzDqX52pu4Tdh1b docker-demo 2 | -------------------------------------------------------------------------------- /demo/files/tomcat/etc/ssh/ssh_host_rsa_key.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDer3R8g1Fz18k7qVCY7wdwkmjATak/MaEjVErVoMTcmmyVgz9LxgviEhZdALm98Ru603VGvxJSR2zl7B4ZP7GA9S66dv6T/OU9v7RWZOcrjcYpGu6NJaY8NWDskJx3MsO50iiLdIy8sVLYbWGL2Ca1qqOpa/nCPRaGlwLGsS5SLrQAVDoEvivvo8FnWf1A8M/uatEtIA8J8nvwirVHSp3eIt9ZDfsu0+153o7mV6VzcqTTgIoCj+C3CK8tw9+H7s0zT96Wt/ph2wy16wAfoQCFi0nKwoEUL71jF6uggHD+0Zn7rC54I/9ovgHJVR0iiCnYUH75ZzDqX52pu4Tdh1b docker-demo 2 | -------------------------------------------------------------------------------- /demo/files/tomcat/etc/supervisord.d/ssh.ini: -------------------------------------------------------------------------------- 1 | [program:sshd] 2 | directory=/usr/local/ 3 | command=/usr/sbin/sshd -D 4 | autostart=true 5 | autorestart=true 6 | redirect_stderr=true 7 | -------------------------------------------------------------------------------- /demo/files/tomcat/etc/supervisord.d/tomcat.ini: -------------------------------------------------------------------------------- 1 | [program:tomcat] 2 | command=/usr/libexec/tomcat/server start ; 程序启动命令 3 | autostart=true ; 在supervisord启动的时候也自动启动 4 | startsecs=10 ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒 5 | autorestart=true ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启 6 | startretries=3 ; 启动失败自动重试次数,默认是3 7 | ; user=tomcat ; 用哪个用户启动进程,默认是root 8 | priority=999 ; 进程启动优先级,默认999,值小的优先启动 9 | redirect_stderr=true ; 把stderr重定向到stdout,默认false 10 | ; stdout_logfile_maxbytes=20MB ; stdout 日志文件大小,默认50MB 11 | ; stdout_logfile_backups = 20 ; stdout 日志文件备份数,默认是10 12 | ; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件) 13 | ; stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out 14 | stopasgroup=false ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程 15 | killasgroup=false ;默认为false,向进程组发送kill信号,包括子进程 16 | -------------------------------------------------------------------------------- /demo/files/tomcat/etc/yum.repos.d/CentOS-Epel.repo: -------------------------------------------------------------------------------- 1 | [epel] 2 | name=Extra Packages for Enterprise Linux 7 - $basearch 3 | baseurl=http://mirrors.aliyun.com/epel/7/$basearch 4 | http://mirrors.aliyuncs.com/epel/7/$basearch 5 | failovermethod=priority 6 | enabled=1 7 | gpgcheck=0 8 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 9 | 10 | [epel-debuginfo] 11 | name=Extra Packages for Enterprise Linux 7 - $basearch - Debug 12 | baseurl=http://mirrors.aliyun.com/epel/7/$basearch/debug 13 | http://mirrors.aliyuncs.com/epel/7/$basearch/debug 14 | failovermethod=priority 15 | enabled=0 16 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 17 | gpgcheck=0 18 | 19 | [epel-source] 20 | name=Extra Packages for Enterprise Linux 7 - $basearch - Source 21 | baseurl=http://mirrors.aliyun.com/epel/7/SRPMS 22 | http://mirrors.aliyuncs.com/epel/7/SRPMS 23 | failovermethod=priority 24 | enabled=0 25 | gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 26 | gpgcheck=0 27 | -------------------------------------------------------------------------------- /demo/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cd $(dirname $0) 6 | 7 | if [ -f ../tars/settings/local.py ]; then 8 | echo "local.py exists, no need to copy sample file" 9 | else 10 | echo "local.py not exists, copying sample file" 11 | cp ../tars/settings/local.py.example ../tars/settings/local.py && echo 'file copied' 12 | fi 13 | -------------------------------------------------------------------------------- /doc/images/API-Application-C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Application-C.png -------------------------------------------------------------------------------- /doc/images/API-Application-List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Application-List.png -------------------------------------------------------------------------------- /doc/images/API-Group-C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Group-C.png -------------------------------------------------------------------------------- /doc/images/API-Group-List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Group-List.png -------------------------------------------------------------------------------- /doc/images/API-Group-RD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Group-RD.png -------------------------------------------------------------------------------- /doc/images/API-Group-U.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Group-U.png -------------------------------------------------------------------------------- /doc/images/API-Package-C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Package-C.png -------------------------------------------------------------------------------- /doc/images/API-Package-List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Package-List.png -------------------------------------------------------------------------------- /doc/images/API-Server-C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Server-C.png -------------------------------------------------------------------------------- /doc/images/API-Server-List.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/API-Server-List.png -------------------------------------------------------------------------------- /doc/images/Admin-Application-New.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Application-New.png -------------------------------------------------------------------------------- /doc/images/Admin-Application-RDL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Application-RDL.png -------------------------------------------------------------------------------- /doc/images/Admin-Group-CU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Group-CU.png -------------------------------------------------------------------------------- /doc/images/Admin-Group-RDL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Group-RDL.png -------------------------------------------------------------------------------- /doc/images/Admin-Overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Overview.png -------------------------------------------------------------------------------- /doc/images/Admin-Package-New1-CU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Package-New1-CU.png -------------------------------------------------------------------------------- /doc/images/Admin-Package-New2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Package-New2-1.png -------------------------------------------------------------------------------- /doc/images/Admin-Package-New2-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Package-New2-2.png -------------------------------------------------------------------------------- /doc/images/Admin-Package-RDL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Package-RDL.png -------------------------------------------------------------------------------- /doc/images/Admin-Server-CU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Server-CU.png -------------------------------------------------------------------------------- /doc/images/Admin-Server-RDL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Admin-Server-RDL.png -------------------------------------------------------------------------------- /doc/images/Demo-Screenshots-Deployment-Configure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Screenshots-Deployment-Configure.png -------------------------------------------------------------------------------- /doc/images/Demo-Screenshots-Deployment-Init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Screenshots-Deployment-Init.png -------------------------------------------------------------------------------- /doc/images/Demo-Screenshots-Deployment-Packages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Screenshots-Deployment-Packages.png -------------------------------------------------------------------------------- /doc/images/Demo-Screenshots-Deployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Screenshots-Deployment.png -------------------------------------------------------------------------------- /doc/images/Demo-Screenshots-Web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Screenshots-Web.png -------------------------------------------------------------------------------- /doc/images/Demo-Services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Demo-Services.png -------------------------------------------------------------------------------- /doc/images/Development-Docker-Configure-DB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Development-Docker-Configure-DB.png -------------------------------------------------------------------------------- /doc/images/Development-Docker-Finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Development-Docker-Finish.png -------------------------------------------------------------------------------- /doc/images/Development-Docker-Services.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Development-Docker-Services.png -------------------------------------------------------------------------------- /doc/images/Development-Screenshots-Web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/doc/images/Development-Screenshots-Web.png -------------------------------------------------------------------------------- /docker-compose-frontend.yml: -------------------------------------------------------------------------------- 1 | frontend_build: 2 | image: node:6 3 | volumes: 4 | - .:/code 5 | working_dir: /code 6 | command: make frontend 7 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | db: 2 | image: mysql:5.7 3 | ports: 4 | - "3306:3306" 5 | environment: 6 | - MYSQL_ROOT_PASSWORD=my-secret-pw 7 | - MYSQL_DATABASE=tars 8 | - MYSQL_USER=tars 9 | - MYSQL_PASSWORD=test1234 10 | - MYSQL_CHARSET=utf8 11 | 12 | backend: 13 | image: redis 14 | ports: 15 | - "6379:6379" 16 | 17 | es: 18 | image: elasticsearch:5 19 | ports: 20 | - '9200:9200' 21 | 22 | worker: 23 | build: . 24 | # command: python manage.py celery -A roll_engine worker --autoreload -l info --settings=tars.settings.docker 25 | command: celery worker -A roll_engine -l info 26 | volumes: 27 | - .:/code 28 | environment: 29 | - C_FORCE_ROOT=1 30 | - DJANGO_SETTINGS_MODULE=tars.settings.docker 31 | links: 32 | - backend 33 | - db 34 | - es 35 | 36 | web: 37 | build: . 38 | command: python manage.py runserver 0.0.0.0:8000 --settings=tars.settings.docker 39 | volumes: 40 | - .:/code 41 | ports: 42 | - "8000:8000" 43 | links: 44 | - db 45 | - backend 46 | - es 47 | 48 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tars.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /requirements/base.txt: -------------------------------------------------------------------------------- 1 | # roll_engine requirements 2 | celery>=3.0,<4.0 3 | django-fsm 4 | 5 | # rest_client requirements 6 | pyyaml 7 | urllib3>=1.21.1,<1.23 8 | requests>=2.6.0 9 | elasticsearch 10 | 11 | # tars requirements 12 | decisionTable 13 | Django>=1.8,<1.9 14 | django-constance>=1.2 15 | django-picklefield 16 | django-filter<=0.11.0 17 | djangorestframework>=3.0.4,<3.1.0 18 | djangorestframework-camel-case 19 | djangorestframework-jsonp 20 | MySQL-python 21 | sqlparse 22 | redis 23 | raven 24 | kafka-python 25 | -------------------------------------------------------------------------------- /requirements/local.txt: -------------------------------------------------------------------------------- 1 | -i http://pypi.douban.com/simple 2 | -r base.txt 3 | 4 | ansible<2.0 5 | django-extensions<1.7 6 | django-debug-toolbar 7 | django-celery>=3.1.16 8 | graphviz 9 | Werkzeug 10 | httpretty 11 | vcrpy 12 | -------------------------------------------------------------------------------- /requirements/production.txt: -------------------------------------------------------------------------------- 1 | -r base.txt 2 | 3 | uwsgi 4 | -------------------------------------------------------------------------------- /rest_client/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import re 4 | from rest_client.clients import ( 5 | get_es_client, 6 | get_salt_client, 7 | ) 8 | 9 | pattern = re.compile("^get_[a-z_]+_client$") 10 | 11 | __all__ = tuple(i for i in globals().keys() if pattern.search(i) is not None) 12 | -------------------------------------------------------------------------------- /rest_client/clients/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from rest_client.utils import camel2underscore 4 | from .es import get_es_client 5 | from .salt import get_salt_client 6 | 7 | __all__ = ('get_es_client', 'get_salt_client',) 8 | 9 | _globals = globals() 10 | 11 | 12 | # Add client to __all__ as get_xxx_client 13 | def __factory(klass): 14 | def func(): 15 | return klass 16 | func.__name__ = 'get_{}_client'.format(camel2underscore(klass.__name__)) 17 | return func 18 | -------------------------------------------------------------------------------- /rest_client/clients/es.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import urlparse 4 | from elasticsearch import Elasticsearch 5 | 6 | from rest_client.decorators import osg 7 | from rest_client.exceptions import ESClientError, ServerResponseException 8 | from .core import JsonClient 9 | 10 | 11 | class ES(JsonClient): 12 | _es = None 13 | _url_base = None 14 | _env = 'default' 15 | 16 | @classmethod 17 | def config(cls, key=None): 18 | return super(ES, cls).config('ES', key) 19 | 20 | 21 | def get_es_client(env='default'): 22 | es_kls = ES 23 | 24 | if es_kls._es is None: 25 | es_kls._env = 'default' 26 | es_kls.build_url_base() 27 | es_kls._es = Elasticsearch(es_kls._url_base) 28 | 29 | return es_kls._es 30 | -------------------------------------------------------------------------------- /roll_engine/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/roll_engine/__init__.py -------------------------------------------------------------------------------- /roll_engine/celery.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | import os 3 | 4 | from django.conf import settings 5 | from celery import Celery 6 | 7 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tars.settings') 8 | 9 | app = Celery('tars') 10 | app.config_from_object('django.conf:settings') 11 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) 12 | 13 | 14 | @app.task(bind=True) 15 | def debug_task(self): 16 | print('Request: {!r}'.format(self.request)) 17 | -------------------------------------------------------------------------------- /roll_engine/constants.py: -------------------------------------------------------------------------------- 1 | # Deployment Statuses 2 | PENDING = 'PENDING' 3 | SMOKING = 'SMOKING' 4 | SMOKE_SUCCESS = 'SMOKE_SUCCESS' 5 | SMOKE_SUCCESS_BRAKED = 'SMOKE_SUCCESS_BRAKED' 6 | SMOKE_FAILURE_BRAKED = 'SMOKE_FAILURE_BRAKED' 7 | SMOKE_FAILURE = 'SMOKE_FAILURE' 8 | SMOKE_BRAKED = 'SMOKE_BRAKED' 9 | BAKING = 'BAKING' 10 | BAKE_SUCCESS = 'BAKE_SUCCESS' 11 | BAKE_SUCCESS_BRAKED = 'BAKE_SUCCESS_BRAKED' 12 | BAKE_FAILURE_BRAKED = 'BAKE_FAILURE_BRAKED' 13 | BAKE_FAILURE = 'BAKE_FAILURE' 14 | BAKE_BRAKED = 'BAKE_BRAKED' 15 | ROLLING_OUT = 'ROLLING_OUT' 16 | ROLLOUT_SUCCESS = 'ROLLOUT_SUCCESS' 17 | ROLLOUT_SUCCESS_BRAKED = 'ROLLOUT_SUCCESS_BRAKED' 18 | ROLLOUT_FAILURE_BRAKED = 'ROLLOUT_FAILURE_BRAKED' 19 | ROLLOUT_FAILURE = 'ROLLOUT_FAILURE' 20 | ROLLOUT_BRAKED = 'ROLLOUT_BRAKED' 21 | SUCCESS = 'SUCCESS' 22 | FAILURE = 'FAILURE' 23 | REVOKED = 'REVOKED' 24 | 25 | 26 | # DeploymentBatch Statuses 27 | PENDING = PENDING 28 | DEPLOYING = 'DEPLOYING' 29 | SUCCESS = SUCCESS 30 | FAILURE = FAILURE 31 | REVOKED = REVOKED 32 | 33 | 34 | # DeploymentTarget Statuses 35 | PENDING = PENDING 36 | DISABLING = 'DISABLING' 37 | DISABLE_SUCCESS = 'DISABLE_SUCCESS' 38 | DISABLE_FAILURE = 'DISABLE_FAILURE' 39 | ENABLING = 'ENABLING' 40 | ENABLE_SUCCESS = 'ENABLE_SUCCESS' 41 | ENABLE_FAILURE = 'ENABLE_FAILURE' 42 | SUCCESS = SUCCESS 43 | FAILURE = FAILURE 44 | REVOKED = REVOKED 45 | -------------------------------------------------------------------------------- /roll_engine/exceptions.py: -------------------------------------------------------------------------------- 1 | class DeploymentError(Exception): 2 | pass 3 | 4 | 5 | class BatchPatternError(DeploymentError): 6 | pass 7 | 8 | 9 | class MetaMissing(DeploymentError): 10 | pass 11 | 12 | 13 | class JobMissing(DeploymentError): 14 | pass 15 | 16 | 17 | class StatusError(DeploymentError): 18 | pass 19 | 20 | 21 | class ActionNotExist(DeploymentError): 22 | pass 23 | 24 | 25 | class ActionNotAllowed(DeploymentError): 26 | pass 27 | 28 | 29 | class ActionFailed(DeploymentError): 30 | pass 31 | -------------------------------------------------------------------------------- /roll_engine/fsm/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import inspect 4 | from functools import wraps 5 | 6 | from django_fsm import transition as fsm_transition 7 | 8 | from roll_engine.models.base import FSMedModel 9 | 10 | 11 | def transition(**kwds): 12 | def decorator(func): 13 | kwds['field'] = FSMedModel._meta.get_field('status') 14 | fsm_trans_func = fsm_transition(**kwds)(func) 15 | 16 | @wraps(func) 17 | def func_wrapper(*args, **kwargs): 18 | return fsm_trans_func(*args, **kwargs) 19 | return func_wrapper 20 | return decorator 21 | 22 | from .deployment import * 23 | from .batch import * 24 | from .target import * 25 | 26 | __all__ = [v for k, v in globals().items() 27 | if not k.startswith('_') and inspect.isclass(v)] 28 | -------------------------------------------------------------------------------- /roll_engine/models/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import inspect 4 | 5 | from .deployments import * 6 | from .batches import * 7 | from .targets import * 8 | from .actions import * 9 | from .configs import * 10 | from .base import FSMedModel 11 | 12 | 13 | __all__ = [v for k, v in globals().items() 14 | if not k.startswith('_') and inspect.isclass(v)] 15 | -------------------------------------------------------------------------------- /roll_engine/models/actions.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from django.db import models 4 | 5 | from roll_engine.db import TimestampedModel 6 | 7 | 8 | class DeploymentAction(TimestampedModel): 9 | action = models.CharField(max_length=255, null=True, blank=True) 10 | message = models.CharField(max_length=255, null=True, blank=True) 11 | operator = models.CharField(max_length=55, null=True, blank=True) 12 | start_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) 13 | 14 | class Meta: 15 | abstract = True 16 | 17 | def __unicode__(self): 18 | return self.action 19 | -------------------------------------------------------------------------------- /roll_engine/models/batches.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | from django.db import models 4 | 5 | from roll_engine.fsm import BatchFSMixin 6 | from roll_engine.mixins import BatchMixin 7 | from roll_engine.exceptions import DeploymentError 8 | from .base import FSMedModel, InheritanceMetaclass 9 | 10 | 11 | class DeploymentBatch(BatchMixin, BatchFSMixin, FSMedModel): 12 | __metaclass__ = InheritanceMetaclass 13 | 14 | index = models.IntegerField(null=True) 15 | pause_time = models.IntegerField(default=0) 16 | FORT_INDEX = 1 17 | 18 | class Meta: 19 | abstract = True 20 | 21 | @classmethod 22 | def validate_meta(cls): 23 | pass 24 | 25 | def get_object(self): 26 | return self 27 | 28 | def is_fort_batch(self): 29 | raise DeploymentError('return boolean to indicate whether a fort batch') 30 | 31 | def save(self, *args, **kwargs): 32 | if self.pk is None: 33 | if self.deployment is not None: 34 | self.pause_time = self.deployment.config.pause_time 35 | super(DeploymentBatch, self).save(*args, **kwargs) 36 | 37 | def is_reach_up_server_threshold(self): 38 | return False 39 | -------------------------------------------------------------------------------- /roll_engine/models/configs.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from roll_engine.db import TimestampedModel 4 | 5 | 6 | class DeploymentConfig(TimestampedModel): 7 | MANUAL = 'm' 8 | AUTO = 'a' 9 | MODE_CHOICES = ( 10 | (MANUAL, 'manual'), 11 | (AUTO, 'auto') 12 | ) 13 | batch_pattern = models.CharField(max_length=300, null=True) 14 | pause_time = models.IntegerField(default=0) 15 | mode = models.CharField(max_length=1, choices=MODE_CHOICES, default=AUTO) 16 | 17 | class Meta: 18 | abstract = True 19 | 20 | def __unicode__(self): 21 | return self.batch_pattern 22 | -------------------------------------------------------------------------------- /roll_engine/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/roll_engine/utils/__init__.py -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = tars 3 | version = 0.1 4 | summary = TARS 5 | description-file = 6 | README.rst 7 | author = TARS 8 | author-email = tars@ctrip.com 9 | 10 | [files] 11 | packages = 12 | tars 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import setuptools 3 | 4 | setuptools.setup( 5 | setup_requires=['pbr'], 6 | pbr=True) 7 | -------------------------------------------------------------------------------- /tars/__init__.py: -------------------------------------------------------------------------------- 1 | from tars.engine.celery_app import app 2 | -------------------------------------------------------------------------------- /tars/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/api/__init__.py -------------------------------------------------------------------------------- /tars/api/filters.py: -------------------------------------------------------------------------------- 1 | from rest_framework.filters import DjangoFilterBackend 2 | 3 | from tars.api.decorators import status, running, ids 4 | 5 | 6 | class StatusFilterBackend(DjangoFilterBackend): 7 | @status() 8 | def filter_queryset(self, request, queryset, view): 9 | queryset = super(StatusFilterBackend, self).filter_queryset( 10 | request, queryset, view) 11 | return queryset 12 | 13 | 14 | class DeploymentFilterBackend(StatusFilterBackend): 15 | @running() 16 | @ids(param='app_id', field='application__id') 17 | def filter_queryset(self, request, queryset, view): 18 | queryset = super(DeploymentFilterBackend, self).filter_queryset( 19 | request, queryset, view) 20 | return queryset 21 | 22 | 23 | class BatchFilterBackend(StatusFilterBackend): 24 | def filter_queryset(self, request, queryset, view): 25 | queryset = super(BatchFilterBackend, self).filter_queryset( 26 | request, queryset, view) 27 | return queryset 28 | -------------------------------------------------------------------------------- /tars/api/permissions.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from django.conf import settings 4 | from constance import config 5 | 6 | from rest_framework import permissions 7 | 8 | from tars.deployment.models import TarsDeploymentAction 9 | from tars.application.models import Application 10 | 11 | logger = logging.getLogger(__name__) 12 | 13 | 14 | class IsDebugMode(permissions.BasePermission): 15 | def has_permission(self, request, view): 16 | if getattr(settings, 'DEBUG', False): 17 | return True 18 | return False 19 | 20 | class PostOnlyAuth(permissions.IsAuthenticated): 21 | 22 | def has_permission(self, request, view): 23 | if request.method == 'POST' and view.action is not None: 24 | 25 | if super(PostOnlyAuth, self).has_permission(request, view): 26 | return True 27 | else: 28 | app_id = request.data.get('application') or view.get_object().application_id 29 | TarsDeploymentAction.objects.create( 30 | action='auth', 31 | operator=request.user.username, 32 | message='permission deny on {} of application {}'.format(view.action, app_id)) 33 | return False 34 | else: 35 | return True 36 | -------------------------------------------------------------------------------- /tars/api/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | from .application import * 2 | from .server import * 3 | from .deployment import * 4 | from .base import LogSerializer 5 | 6 | __all__ = globals() 7 | -------------------------------------------------------------------------------- /tars/api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/api/tests/__init__.py -------------------------------------------------------------------------------- /tars/api/tests/test_group.py: -------------------------------------------------------------------------------- 1 | from rest_framework.test import APITestCase 2 | 3 | from tars.application.models import Application 4 | from tars.server.models import Group 5 | 6 | 7 | class TestGroupAPI(APITestCase): 8 | url = '/api/v1/groups' 9 | data = [ 10 | { 11 | 'name': 'group1', 12 | 'group_id': 1, 13 | 'site_name': 'Ctrip', 14 | 'fort': 'FORT1' 15 | }, 16 | { 17 | 'name': 'group2', 18 | 'group_id': 2, 19 | 'site_name': 'Ctrip', 20 | 'fort': 'FORT2' 21 | } 22 | ] 23 | 24 | def setUp(self): 25 | app_data = {'name': 'app1', 'id': 1, 26 | 'environment': 'uat', 'ignore_fort': False} 27 | app = Application.objects.create(**app_data) 28 | 29 | for item in self.data: 30 | Group.objects.create(application=app, **item) 31 | 32 | def test_sync(self): 33 | pass 34 | -------------------------------------------------------------------------------- /tars/api/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | 3 | from rest_framework import routers 4 | 5 | from tars.api.views import application as application_views 6 | from tars.api.views import server as server_views 7 | from tars.api.views import deployment as deployment_views 8 | from tars.api.views import log as log_views 9 | 10 | 11 | router = routers.DefaultRouter(trailing_slash=False) 12 | 13 | router.register(r'applications', application_views.ApplicationViewSet) 14 | router.register(r'packages', application_views.PackageViewSet) 15 | router.register(r'groups', server_views.GroupViewSet) 16 | router.register(r'join_groups', server_views.JoinedGroupViewSet) 17 | router.register(r'servers', server_views.ServerViewSet) 18 | router.register(r'deployments', deployment_views.DeploymentViewSet, 19 | base_name='deployment') 20 | router.register(r'configs', deployment_views.DeploymentConfigViewSet) 21 | router.register(r'batches', deployment_views.DeploymentBatchViewSet) 22 | router.register(r'targets', deployment_views.DeploymentTargetViewSet) 23 | router.register(r'actions', deployment_views.DeploymentActionViewSet) 24 | 25 | urlpatterns = [ 26 | url(r'^logs', log_views.LogViewSet.as_view({'get': 'list'})), 27 | url(r'^', include(router.urls)), 28 | ] 29 | -------------------------------------------------------------------------------- /tars/api/views/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/api/views/__init__.py -------------------------------------------------------------------------------- /tars/application/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/application/__init__.py -------------------------------------------------------------------------------- /tars/application/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from tars.application import models 4 | 5 | 6 | class ApplicationAdmin(admin.ModelAdmin): 7 | list_display = ('name',) 8 | admin.site.register(models.Application, ApplicationAdmin) 9 | 10 | 11 | class PackageAdmin(admin.ModelAdmin): 12 | list_display = ('name', 'version', 'application') 13 | admin.site.register(models.Package, PackageAdmin) 14 | -------------------------------------------------------------------------------- /tars/deployment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/deployment/__init__.py -------------------------------------------------------------------------------- /tars/deployment/admin.py: -------------------------------------------------------------------------------- 1 | from decisionTable import DecisionTable 2 | 3 | from constance.admin import ConstanceAdmin, ConstanceForm, Config 4 | from constance import LazyConfig 5 | 6 | from django.contrib import admin 7 | 8 | from tars.deployment import models 9 | 10 | 11 | config = LazyConfig() 12 | 13 | class CustomConstanceForm(ConstanceForm): 14 | def clean(self): 15 | cleaned_data = super(CustomConstanceForm, self).clean() 16 | 17 | dt_keys = [k for k in cleaned_data.keys() if 'DECISION_TABLE' in k] 18 | # validate decision table string format 19 | try: 20 | for key in dt_keys: 21 | dt = DecisionTable(cleaned_data[key]) 22 | if not dt.decisions: 23 | self.add_error(key, 'The decisions in your input value is empty') 24 | except ValueError as e: 25 | self.add_error(key, e) 26 | 27 | 28 | class ConfigAdmin(ConstanceAdmin): 29 | change_list_template = 'constance_change_list.html' 30 | change_list_form = CustomConstanceForm 31 | 32 | 33 | admin.site.unregister([Config]) 34 | admin.site.register([Config], ConfigAdmin) 35 | -------------------------------------------------------------------------------- /tars/deployment/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .configs import TarsDeploymentConfig 2 | from .deployments import TarsDeployment, TarsFortDeployment 3 | from .actions import TarsDeploymentAction 4 | from .batches import TarsDeploymentBatch 5 | from .targets import TarsDeploymentTarget 6 | 7 | __all__ = (TarsDeploymentConfig, TarsDeployment, TarsFortDeployment, 8 | TarsDeploymentAction, TarsDeploymentBatch, TarsDeploymentTarget) 9 | -------------------------------------------------------------------------------- /tars/deployment/models/actions.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | from deployments import TarsDeployment 4 | from roll_engine.models import DeploymentAction 5 | 6 | 7 | class TarsDeploymentAction(DeploymentAction): 8 | deployment = models.ForeignKey( 9 | TarsDeployment, related_name='actions', db_constraint=False, null=True) 10 | finish_time = models.DateTimeField(auto_now_add=True, null=True, blank=True) 11 | 12 | class Meta: 13 | db_table = 'deployment_actions' 14 | 15 | def __unicode__(self): 16 | return self.action 17 | -------------------------------------------------------------------------------- /tars/deployment/models/configs.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from roll_engine.models import DeploymentConfig 3 | 4 | 5 | class TarsDeploymentConfig(DeploymentConfig): 6 | verify_timeout = models.IntegerField(null=True) 7 | startup_timeout = models.IntegerField(null=True) 8 | ignore_verify_result = models.BooleanField(default=False) 9 | restart_app_pool = models.BooleanField(default=False) 10 | 11 | class Meta: 12 | db_table = 'deployment_configs' 13 | 14 | def __unicode__(self): 15 | return self.batch_pattern 16 | -------------------------------------------------------------------------------- /tars/deployment/templatetags/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctripcorp/tars/d7954fccaf1a17901f22d844d84c5663a3d79c11/tars/deployment/templatetags/__init__.py -------------------------------------------------------------------------------- /tars/deployment/templatetags/app_filters.py: -------------------------------------------------------------------------------- 1 | from decisionTable import DecisionTable 2 | from django import template 3 | from django.template.defaultfilters import stringfilter 4 | 5 | 6 | register = template.Library() 7 | 8 | DECISION_TABLE_TEMPLATE = ''' 9 |
clone
method in class
13 | * Object
has been called to clone an object, but that
14 | * the object's class does not implement the Cloneable
15 | * interface.
16 | *
17 | * Applications that override the clone
method can also
18 | * throw this exception to indicate that an object could not or
19 | * should not be cloned.
20 | *
21 | * @author unascribed
22 | * @see java.lang.Cloneable
23 | * @see java.lang.Object#clone()
24 | * @since JDK1.0
25 | */
26 | $import("js.lang.Exception", "BootstrapClassLoader");
27 | Class.forName({
28 | name: "class js.lang.CloneNotSupportedException extends js.lang.Exception",
29 | "private name": "js.lang.CloneNotSupportedException", // 错误名
30 | "private number": 109
31 | // 错误号
32 |
33 | });
34 |
35 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/Error.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 | Class.forName({
11 | name: "class Error",
12 | alias: "js.lang.Error",
13 |
14 | "private name": "js.lang.Error", // 错误名
15 | "private number": 1,
16 |
17 | Error: function(message, fileName, lineNumber, stack) {
18 | this.message = message;
19 | this.fileName = fileName;
20 | this.stack = stack;
21 | this.lineNumber = lineNumber;
22 | },
23 | 'static init': function() {
24 | var methods = {},
25 | __methods = js.lang.Throwable.$class.getMethods(),
26 | __length = __methods.length,
27 | __index = 0;
28 | for (; __index < __length; __index++) {
29 | methods[__methods[__index]._name] = __methods[__index]._value;
30 | }
31 | Object.extend(Error.prototype, methods);
32 | }
33 | });
34 |
35 | js.lang.Error.init();
36 |
37 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/EvalError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 | $import("js.lang.Throwable", "BootstrapClassLoader");
12 | Class.forName({
13 | name: "class EvalError",
14 | alias: "js.lang.EvalError",
15 |
16 | "private name": "js.lang.EvalError", // 错误名
17 | "private number": 2,
18 |
19 | EvalError: function() {}
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/Exception.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | Class.forName({
9 | name: "class js.lang.Exception extends js.lang.Throwable",
10 |
11 | "private name": "js.lang.Exception", // 错误名
12 | "private number": 0, // 错误号
13 |
14 | Exception: function(message, fileName, lineNumber, stack) {
15 | this.message = message;
16 | this.fileName = fileName;
17 | this.stack = stack;
18 | this.lineNumber = lineNumber;
19 | }
20 |
21 | });
22 |
23 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/Function.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 | Class.forName({
12 | name: "class Function",
13 | alias: "js.lang.Function",
14 | Function: function() {}
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/IllegalAccessException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.lang.IllegalAccessException extends js.lang.Exception",
11 | "private name": "js.lang.IllegalAccessException", // 错误名
12 | "private number": 101
13 | // 错误号
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/IllegalArgumentException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.lang.IllegalArgumentException extends js.lang.Exception",
11 | "private name": "js.lang.IllegalArgumentException", // 错误名
12 | "private number": 102
13 | // 错误号
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/IllegalStateException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.lang.IllegalStateException extends js.lang.Exception",
11 | "private name": "js.lang.IllegalStateException", // 错误名
12 | "private number": 103
13 | // 错误号
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/IndexOutOfBoundsException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.lang.IndexOutOfBoundsException extends js.lang.Exception",
11 | "private name": "js.lang.IndexOutOfBoundsException", // 错误名
12 | "private number": 104
13 | // 错误号
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/InternalError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2015 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2015年2月10日
9 | */
10 | Class.forName({
11 | name: "class js.lang.InternalError extends js.lang.Error",
12 |
13 | "private name": "js.lang.InternalError", // 错误名
14 | "private number": 99,
15 |
16 |
17 | });
18 |
19 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/NoSuchFieldException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | Class.forName({
9 | name: "class js.lang.NoSuchFieldException extends js.lang.Exception",
10 | "private name": "js.lang.NoSuchFieldException",
11 | "private number": 105
12 | });
13 |
14 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/NoSuchMethodException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | Class.forName({
9 | name: "class js.lang.NoSuchMethodException extends js.lang.Exception",
10 | "private name": "js.lang.NoSuchMethodException",
11 | "private number": 106
12 | });
13 |
14 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/NullPointerException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.lang.NullPointerException extends js.lang.Exception",
11 | "private name": "js.lang.NullPointerException",
12 | "private number": 107
13 | });
14 |
15 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/Number.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 | Class.forName({
12 | name: "class Number",
13 |
14 | alias: "js.lang.Number",
15 | Number: function() {},
16 | "public equals": function(s) {
17 | return Object.isNumber(s) && this == s;
18 | }
19 |
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/RangeError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 | $import("js.lang.Throwable", "BootstrapClassLoader");
12 | Class.forName({
13 | name: "class RangeError",
14 | alias: "js.lang.RangeError",
15 |
16 | "private name": "js.lang.RangeError", // 错误名
17 | "private number": 3,
18 |
19 | RangeError: function() {}
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/ReferenceError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 | $import("js.lang.Throwable", "BootstrapClassLoader");
11 | Class.forName({
12 | name: "class ReferenceError",
13 | alias: "js.lang.ReferenceError",
14 |
15 | "private name": "js.lang.ReferenceError", // 错误名
16 | "private number": 4,
17 |
18 | ReferenceError: function() {}
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/RegExp.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 | Class.forName({
12 | name: "class RegExp",
13 | alias: "js.lang.RegExp",
14 | RegExp: function() {}
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/String.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 10, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "class String",
11 | alias: "js.lang.String",
12 | String: function() {},
13 | "public trim": function() {
14 | var re = /^\s+|\s+$/g;
15 | return function() {
16 | return this.replace(re, "");
17 | };
18 | }(),
19 | "public equals": function(s) {
20 | return Object.isString(s) && this == s;
21 | },
22 | getLength: function() {
23 | return this.length;
24 | }
25 |
26 | });
27 |
28 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/SyntaxError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 | $import("js.lang.Throwable", "BootstrapClassLoader");
11 | Class.forName({
12 | name: "class SyntaxError",
13 | alias: "js.lang.SyntaxError",
14 |
15 | "private name": "js.lang.SyntaxError", // 错误名
16 | "private number": 5,
17 |
18 | SyntaxError: function() {}
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/TypeError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 | $import("js.lang.Throwable", "BootstrapClassLoader");
11 | Class.forName({
12 | name: "class TypeError",
13 | alias: "js.lang.TypeError",
14 |
15 | "private name": "js.lang.TypeError", // 错误名
16 | "private number": 6,
17 |
18 | TypeError: function() {}
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/URIError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 | $import("js.lang.Throwable", "BootstrapClassLoader");
11 |
12 | Class.forName({
13 | name: "class URIError",
14 | alias: "js.lang.URIError",
15 |
16 | "private name": "js.lang.URIError", // 错误名
17 | "private number": 7,
18 |
19 | URIError: function() {}
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/UnsupportedOperationException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class
10 | .forName({
11 | name: "class js.lang.UnsupportedOperationException extends js.lang.Exception",
12 | "private name": "js.lang.UnsupportedOperationException", // 错误名
13 | "private number": 108
14 | // 错误号
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/reflect/Constructor.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 14, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "abstract class js.lang.reflect.Constructor extends Object"
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/reflect/Field.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 14, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "public final class js.lang.reflect.Field extends Object",
11 | "@Setter @Getter private _declaringClass": null,
12 | "@Setter @Getter private _name": null,
13 | "@Setter @Getter private _modifiers": null,
14 | "@Setter @Getter private _annotations": null,
15 | "@Setter @Getter private _value": null,
16 |
17 | Field: function(name, value, declaringClass, modifiers, annotations) {
18 | this._name = name;
19 | this._declaringClass = declaringClass;
20 | this._modifiers = modifiers;
21 | this._annotations = annotations;
22 | this._value = value;
23 |
24 | },
25 | clone: function() {
26 | return this;
27 | },
28 | "set": function(obj, value) {
29 | obj[this._name] = value;
30 | },
31 | "get": function(obj) {
32 | return obj[this._name];
33 | }
34 | });
35 | js.lang.reflect.Field.loaded = true;
36 |
37 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/lang/reflect/InvocationTargetException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 14, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class
10 | .forName({
11 | name: "class js.lang.reflect.InvocationTargetException extends js.lang.Exception",
12 | "private name": "InvocationTargetException", // 错误名
13 | "private number": 100
14 | // 错误号
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/net/Http.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 14, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "class js.net.http.Http extends Object",
11 | "public static REQUEST": {
12 | TYPE: ["GET", "HEAD", "PUT", "DELETE", "POST", "OPTIONS"]
13 | },
14 | Http: function() {}
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/net/HttpURLConnection.js:
--------------------------------------------------------------------------------
1 | $import("js.net.URLConnection");
2 |
3 | Class.forName({
4 | name: "class js.net.HttpURLConnection extends js.net.URLConnection",
5 |
6 | "public static getConnection": function() {
7 | var xhr = null;
8 |
9 | if (typeof XMLHttpRequest != 'undefined') {
10 | xhr = new XMLHttpRequest();
11 | } else {
12 | xhr = new ActiveXObject('Microsoft.XMLHTTP');
13 | }
14 | return xhr;
15 | }
16 | });
17 |
18 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/net/Rest.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 14, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "class js.net.http.Rest extends Object",
11 | Rest: function() {},
12 | build: (function() {
13 | var regx1 = /\/{2,}/g,
14 | regx2 = /\/$/g;
15 | return function() {
16 | if (arguments.length > 0) {
17 | if (!Object.isEmpty(arguments[0]) && Object.isString(arguments[0])) {
18 | var _method = arguments[0].toUpperCase();
19 | if (com.js.net.http.HTTP.REQUEST.TYPE.contains(_method)) {
20 | var temp = new StringBuffer();
21 | var url = temp.append("").applys(
22 | Array.prototype.slice.call(arguments, 1))
23 | .toString("/");
24 | temp.clear();
25 | temp.append(
26 | url.trim().replace(regx1, "/").replace(regx2,
27 | "")).append("?_method=")
28 | .append(_method);
29 | return temp.toString();
30 | }
31 | }
32 | }
33 | return null;
34 | };
35 | })()
36 | });
37 |
38 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/net/URLConnection.js:
--------------------------------------------------------------------------------
1 | Class.forName({
2 | name: "class js.net.URLConnection extends Object",
3 |
4 | });
5 |
6 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/test/AssertionError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JSRT JavaScript Library 0.2.1
3 | * lico.atom@gmail.com
4 | *
5 | * Copyright 2008, 2014 Atom Union, Inc.
6 | * Released under the MIT license
7 | *
8 | * Date: 2014年6月25日
9 | */
10 |
11 |
12 | $import("js.lang.Error", "BootstrapClassLoader");
13 | Class.forName({
14 | name: "class js.test.AssertionError extends js.lang.Error",
15 | "private name": "js.test.AssertionError", // 错误名
16 | "private number": -1
17 |
18 |
19 | });
20 |
21 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/text/Format.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 16, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "abstract class js.text.Format extends Object",
11 | Format: function() {},
12 |
13 | /** 格式化一个对象以生成一个字符串。 */
14 | 'abstract format': function(obj) {},
15 |
16 | /** 从给定字符串的开始处分析文本以生成一个对象。 */
17 | 'abstract parse': function(source) {}
18 | });
19 |
20 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/Entry.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "class js.util.Entry extends Object",
11 | "private _key": null,
12 | "private _value": null,
13 | Entry: function(key, value) {
14 | this._key = key;
15 | this._value = value;
16 | },
17 | "clone": function() {
18 | var key = this._key ? this._key.clone() : this._key;
19 | var value = this._value ? this._value.clone() : this._value;
20 | return new js.util.Entry(key, value);
21 | },
22 | getKey: function() {
23 | return this._key;
24 | },
25 | getValue: function() {
26 | return this._value;
27 | },
28 | setValue: function(val) {
29 | this._value = _val;
30 | }
31 | });
32 |
33 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/EntrySet.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Set", "BootstrapClassLoader");
10 |
11 | Class.forName({
12 | name: "class js.util.EntrySet extends js.util.Set",
13 | "private _element": null,
14 | EntrySet: function(element) {
15 | this._element = element;
16 | },
17 | iterator: function() {
18 | return new js.util.HashIterator(this._element);
19 | },
20 | size: function() {
21 | return this._element.size();
22 | }
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/HashSet.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Set", "BootstrapClassLoader");
10 | $import("js.util.HashMap", "BootstrapClassLoader");
11 |
12 | Class.forName({
13 | name: "class js.util.HashSet extends js.util.Set",
14 |
15 | "private _table": null,
16 | HashSet: function() {
17 | this._table = new js.util.HashMap();
18 | },
19 |
20 | iterator: function() {
21 | return this._table.keySet().iterator();
22 | },
23 |
24 | size: function() {
25 | return this._table.size();
26 | },
27 |
28 | isEmpty: function() {
29 | return this._table.isEmpty();
30 | },
31 |
32 | contains: function(o) {
33 | return this._table.containsKey(o);
34 | },
35 |
36 | add: function(e) {
37 | return this._table.put(e, null);
38 | },
39 |
40 | remove: function(o) {
41 | this._table.remove(o);
42 | return o;
43 | },
44 |
45 | clear: function() {
46 | this._table.clear();
47 | }
48 | });
49 |
50 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/Iterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | Class.forName({
10 | name: "class js.util.Iterator extends Object",
11 | "private _element": null,
12 | "private _cursor": 0,
13 | "private _lastRet": -1,
14 | Iterator: function(element) {
15 | this._element = element || [];
16 | },
17 |
18 | hasNext: function() {
19 | return this._cursor < this._element.size();
20 | },
21 |
22 | next: function() {
23 | try {
24 | var next = this._element.get(this._cursor);
25 | this._lastRet = this._cursor++;
26 | return next;
27 | } catch (e) {
28 | throw new js.lang.IndexOutOfBoundsException("Index: " + this._cursor + ", Size: " + this._element.size() + ",Message:" + e.getMessage());
29 | }
30 | },
31 | remove: function() {
32 | if (this._lastRet === -1)
33 | throw new js.lang.IllegalStateException();
34 | try {
35 | this._element.removeAt(this._lastRet);
36 | if (this._lastRet < this._cursor)
37 | this._cursor--;
38 | this._lastRet = -1;
39 | } catch (e) {
40 | throw new js.lang.IndexOutOfBoundsException();
41 | }
42 | }
43 | });
44 |
45 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/KeyIterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.HashIterator", "BootstrapClassLoader");
10 |
11 | Class
12 | .forName({
13 | name: "class js.util.KeyIterator extends js.util.HashIterator",
14 | next: function() {
15 | try {
16 | var next = this._element._table[this._element._hashArray[this._cursor]];
17 | this._lastRet = this._cursor++;
18 | return next.getKey();
19 | } catch (e) {
20 | throw new js.lang.IndexOutOfBoundsException("Index: " + this._cursor + ", Size: " + this._element.size() + ",Message:" + e.getMessage());
21 | }
22 | }
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/KeySet.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Set", "BootstrapClassLoader");
10 | $import("js.util.KeyIterator", "BootstrapClassLoader");
11 |
12 | Class.forName({
13 | name: "class js.util.KeySet extends js.util.Set",
14 | "private _element": null,
15 | KeySet: function(element) {
16 | this._element = element;
17 | },
18 | iterator: function() {
19 | return new js.util.KeyIterator(this._element);
20 | },
21 | size: function() {
22 | return this._element.size();
23 | }
24 | });
25 |
26 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/LinkIterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Iterator", "BootstrapClassLoader");
10 |
11 | Class.forName({
12 | name: "class js.util.LinkIterator extends js.util.Iterator",
13 |
14 | LinkIterator: function(element, index) {
15 | this._element = element;
16 | this._cursor = index || 0;
17 | },
18 |
19 | "hasPrevious": function() {
20 | return this._cursor > 0;
21 | },
22 |
23 | "previous": function() {
24 | try {
25 | var i = this._cursor - 1,
26 | previous = this._element.get(i);
27 | this._lastRet = this._cursor = i;
28 | return previous;
29 | } catch (e) {
30 | throw new js.lang.IndexOutOfBoundsException();
31 | }
32 | },
33 |
34 | "nextIndex": function() {
35 | return this._cursor;
36 | },
37 |
38 | "previousIndex": function() {
39 | return this._cursor - 1;
40 | }
41 | });
42 |
43 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/NoSuchElementException.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 12, 2014
7 | */
8 | $import("js.lang.Exception", "BootstrapClassLoader");
9 | Class.forName({
10 | name: "class js.util.NoSuchElementException extends js.lang.Exception",
11 | "private name": "js.util.NoSuchElementException", // 错误名
12 | "private number": 801
13 | // 错误号
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/Set.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Collection", "BootstrapClassLoader");
10 |
11 | Class.forName({
12 | name: "class js.util.Set extends js.util.Collection"
13 |
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/TreeMap.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Map", "BootstrapClassLoader");
10 |
11 | Class.forName({
12 | name: "class js.util.TreeMap extends js.util.Map"
13 | });
14 |
15 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/TreeSet.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.Set", "BootstrapClassLoader");
10 |
11 | Class.forName({
12 | name: "class js.util.TreeSet extends js.util.Set"
13 |
14 | });
15 |
16 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/ValueIterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.HashIterator", "BootstrapClassLoader");
10 |
11 | Class
12 | .forName({
13 | name: "class js.util.ValueIterator extends js.util.HashIterator",
14 | next: function() {
15 | try {
16 | var next = this._element._table[this._element._hashArray[this._cursor]];
17 | this._lastRet = this._cursor++;
18 | return next.getValue();
19 | } catch (e) {
20 | throw new js.lang.IndexOutOfBoundsException("Index: " + this._cursor + ", Size: " + this._element.size() + ",Message:" + e.getMessage());
21 | }
22 | }
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/main/js/js/util/ValueList.js:
--------------------------------------------------------------------------------
1 | /*
2 | * ! JSRT JavaScript Library 0.1.1 lico.atom@gmail.com
3 | *
4 | * Copyright 2008, 2014 Atom Union, Inc. Released under the MIT license
5 | *
6 | * Date: Feb 11, 2014
7 | */
8 |
9 | $import("js.util.List", "BootstrapClassLoader");
10 | $import("js.util.ValueIterator", "BootstrapClassLoader");
11 |
12 | Class.forName({
13 | name: "class js.util.ValueList extends js.util.List",
14 |
15 | "private _element": null,
16 | ValueList: function(element) {
17 | this._element = element;
18 | },
19 | iterator: function() {
20 | return new js.util.ValueIterator(this._element);
21 | },
22 | size: function() {
23 | return this._element.size();
24 | },
25 |
26 | "removeAt": function(index) {
27 | this.rangeCheck();
28 | return this._element._table.splice(index, 1);
29 | },
30 |
31 | "get": function(index) {
32 | this.rangeCheck();
33 | return this._element._table[index];
34 | },
35 |
36 | "subList": function(fromIndex, toIndex) {
37 | return this._element._table.slice(fromIndex, toIndex);
38 | },
39 |
40 | "set": function(index, element) {
41 | this.rangeCheck(index);
42 | var oldValue = this._element._table[index];
43 | this._element._table[index] = element;
44 | return oldValue;
45 | }
46 |
47 | });
48 |
49 |
--------------------------------------------------------------------------------
/tars/surface/static/jre/src/test/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{% trans "We're sorry, but the requested page could not be found." %}
11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /tars/surface/templates/admin/500.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base_site.html" %} 2 | {% load i18n %} 3 | 4 | {% block breadcrumbs %} 5 | 9 | {% endblock %} 10 | 11 | {% block title %}{% trans 'Server error (500)' %}{% endblock %} 12 | 13 | {% block content %} 14 |{% trans "There's been an error. It's been reported to the site administrators via email and should be fixed shortly. Thanks for your patience." %}
16 | 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /tars/surface/templates/admin/actions.html: -------------------------------------------------------------------------------- 1 | {% load i18n %} 2 |{% trans "First, enter a username and password. Then, you'll be able to edit more user options." %}
7 | {% else %} 8 |{% trans "Enter a username and password." %}
9 | {% endif %} 10 | {% endblock %} 11 | 12 | {% block after_field_sets %} 13 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /tars/surface/templates/admin/base_site.html: -------------------------------------------------------------------------------- 1 | {% extends "admin/base.html" %} 2 | {% load i18n %} 3 | 4 | {% block title %}{{ title }} | {% 'Tars site admin' %}{% endblock %} 5 | 6 | {% block branding %} 7 |{% trans "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." %}
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /tars/surface/templates/admin/pagination.html: -------------------------------------------------------------------------------- 1 | {% load admin_list %} 2 | {% load i18n %} 3 |4 | {% if pagination_required %} 5 | {% for i in page_range %} 6 | {% paginator_number cl i %} 7 | {% endfor %} 8 | {% endif %} 9 | {{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %} 10 | {% if show_all_url %} {% trans 'Show all' %}{% endif %} 11 | {% if cl.formset and cl.result_count %}{% endif %} 12 |
13 | -------------------------------------------------------------------------------- /tars/surface/templates/admin/popup_response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |{% trans "Setting" %} | 11 |{% trans "Value" %} | 12 |
---|---|
{{ name }} | 18 |{{ value|pprint }} |
19 |