ambari-server.py 116 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405
  1. #!/usr/bin/env python2.6
  2. '''
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. '''
  17. import optparse
  18. from pprint import pprint
  19. import shlex
  20. import sys
  21. import os
  22. import signal
  23. import subprocess
  24. import re
  25. import string
  26. import glob
  27. import platform
  28. import shutil
  29. import stat
  30. import fileinput
  31. import urllib2
  32. import time
  33. import getpass
  34. import socket
  35. import datetime
  36. import socket
  37. import tempfile
  38. import random
  39. import pwd
  40. # debug settings
  41. VERBOSE = False
  42. SILENT = False
  43. SERVER_START_DEBUG = False
  44. # action commands
  45. SETUP_ACTION = "setup"
  46. START_ACTION = "start"
  47. STOP_ACTION = "stop"
  48. RESET_ACTION = "reset"
  49. UPGRADE_ACTION = "upgrade"
  50. UPGRADE_STACK_ACTION = "upgradestack"
  51. UPDATE_METAINFO_ACTION = "update-metainfo"
  52. STATUS_ACTION = "status"
  53. SETUP_HTTPS_ACTION = "setup-https"
  54. LDAP_SETUP_ACTION = "setup-ldap"
  55. ENCRYPT_PASSWORDS_ACTION = "encrypt-passwords"
  56. # selinux commands
  57. GET_SE_LINUX_ST_CMD = "/usr/sbin/sestatus"
  58. SE_SETENFORCE_CMD = "setenforce 0"
  59. SE_STATUS_DISABLED = "disabled"
  60. SE_STATUS_ENABLED = "enabled"
  61. SE_MODE_ENFORCING = "enforcing"
  62. SE_MODE_PERMISSIVE = "permissive"
  63. # iptables commands
  64. IP_TBLS_ST_CMD = "/sbin/service iptables status"
  65. IP_TBLS_STOP_CMD = "/sbin/service iptables stop"
  66. IP_TBLS_ENABLED = "Firewall is running"
  67. IP_TBLS_DISABLED = "Firewall is stopped.\n"
  68. IP_TBLS_SRVC_NT_FND = "iptables: unrecognized service"
  69. # server commands
  70. ambari_provider_module_option = ""
  71. ambari_provider_module = os.environ.get('AMBARI_PROVIDER_MODULE')
  72. # Non-root user setup commands
  73. NR_USER_PROPERTY = "ambari-server.user"
  74. NR_USER_COMMENT = "Ambari user"
  75. NR_GET_OWNER_CMD = 'stat -c "%U" {0}'
  76. NR_USERADD_CMD = 'useradd -M --comment "{1}" ' \
  77. '--shell /sbin/nologin -d /var/lib/ambari-server/keys/ {0}'
  78. NR_SET_USER_COMMENT_CMD = 'usermod -c "{0}" {1}'
  79. NR_CHMOD_CMD = 'chmod {0} {1} {2}'
  80. NR_CHOWN_CMD = 'chown {0} {1} {2}'
  81. RECURSIVE_RM_CMD = 'rm -rf {0}'
  82. # openssl command
  83. EXPRT_KSTR_CMD = "openssl pkcs12 -export -in {0} -inkey {1} -certfile {0} -out {3} -password pass:{2} -passin pass:{2}"
  84. CHANGE_KEY_PWD_CND = 'openssl rsa -in {0} -des3 -out {0}.secured -passout pass:{1}'
  85. GET_CRT_INFO_CMD = 'openssl x509 -dates -subject -in {0}'
  86. # constants
  87. STACK_NAME_VER_SEP = "-"
  88. JAVA_SHARE_PATH="/usr/share/java"
  89. # terminal styles
  90. BOLD_ON='\033[1m'
  91. BOLD_OFF='\033[0m'
  92. #Common messages
  93. PRESS_ENTER_MSG="Press <enter> to continue."
  94. #SSL certificate metainfo
  95. COMMON_NAME_ATTR='CN'
  96. NOT_BEFORE_ATTR='notBefore'
  97. NOT_AFTER_ATTR='notAfter'
  98. if ambari_provider_module is not None:
  99. ambari_provider_module_option = "-Dprovider.module.class=" +\
  100. ambari_provider_module + " "
  101. SERVER_START_CMD="{0}" + os.sep + "bin" + os.sep +\
  102. "java -server -XX:NewRatio=3 "\
  103. "-XX:+UseConcMarkSweepGC " +\
  104. "-XX:-UseGCOverheadLimit -XX:CMSInitiatingOccupancyFraction=60 " +\
  105. ambari_provider_module_option +\
  106. os.getenv('AMBARI_JVM_ARGS','-Xms512m -Xmx2048m') +\
  107. " -cp {1}"+ os.pathsep + "{2}" +\
  108. " org.apache.ambari.server.controller.AmbariServer "\
  109. ">/var/log/ambari-server/ambari-server.out 2>&1 &" \
  110. " echo $! > {3}" # Writing pidfile
  111. SERVER_START_CMD_DEBUG="{0}" + os.sep + "bin" + os.sep +\
  112. "java -server -XX:NewRatio=2 -XX:+UseConcMarkSweepGC " +\
  113. ambari_provider_module_option +\
  114. os.getenv('AMBARI_JVM_ARGS','-Xms512m -Xmx2048m') +\
  115. " -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,"\
  116. "server=y,suspend=n -cp {1}"+ os.pathsep + "{2}" +\
  117. " org.apache.ambari.server.controller.AmbariServer &" \
  118. " echo $! > {3}" # Writing pidfile
  119. SECURITY_PROVIDER_GET_CMD="{0}" + os.sep + "bin" + os.sep + "java -cp {1}" +\
  120. os.pathsep + "{2} " +\
  121. "org.apache.ambari.server.security.encryption" +\
  122. ".CredentialProvider GET {3} {4} {5} " +\
  123. "> /var/log/ambari-server/ambari-server.out 2>&1"
  124. SECURITY_PROVIDER_PUT_CMD="{0}" + os.sep + "bin" + os.sep + "java -cp {1}" +\
  125. os.pathsep + "{2} " +\
  126. "org.apache.ambari.server.security.encryption" +\
  127. ".CredentialProvider PUT {3} {4} {5} " +\
  128. "> /var/log/ambari-server/ambari-server.out 2>&1"
  129. SECURITY_PROVIDER_KEY_CMD="{0}" + os.sep + "bin" + os.sep + "java -cp {1}" +\
  130. os.pathsep + "{2} " +\
  131. "org.apache.ambari.server.security.encryption" +\
  132. ".MasterKeyServiceImpl {3} {4} {5} " +\
  133. "> /var/log/ambari-server/ambari-server.out 2>&1"
  134. SECURITY_KEYS_DIR = "security.server.keys_dir"
  135. SECURITY_MASTER_KEY_LOCATION = "security.master.key.location"
  136. SECURITY_KEY_IS_PERSISTED = "security.master.key.ispersisted"
  137. SECURITY_KEY_ENV_VAR_NAME = "AMBARI_SECURITY_MASTER_KEY"
  138. SECURITY_MASTER_KEY_FILENAME = "master"
  139. SECURITY_IS_ENCRYPTION_ENABLED = "security.passwords.encryption.enabled"
  140. SSL_KEY_DIR = 'security.server.keys_dir'
  141. SSL_API_PORT = 'client.api.ssl.port'
  142. SSL_API = 'api.ssl'
  143. SSL_SERVER_CERT_NAME = 'client.api.ssl.cert_name'
  144. SSL_SERVER_KEY_NAME = 'client.api.ssl.key_name'
  145. SSL_CERT_FILE_NAME = "https.crt"
  146. SSL_KEY_FILE_NAME = "https.key"
  147. SSL_KEYSTORE_FILE_NAME = "https.keystore.p12"
  148. SSL_KEY_PASSWORD_FILE_NAME = "https.pass.txt"
  149. SSL_KEY_PASSWORD_LENGTH = 50
  150. DEFAULT_SSL_API_PORT = 8443
  151. SSL_DATE_FORMAT = '%b %d %H:%M:%S %Y GMT'
  152. JDBC_RCA_PASSWORD_ALIAS = "ambari.db.password"
  153. CLIENT_SECURITY_KEY = "client.security"
  154. LDAP_MGR_PASSWORD_ALIAS = "ambari.ldap.manager.password"
  155. LDAP_MGR_PASSWORD_PROPERTY = "authentication.ldap.managerPassword"
  156. LDAP_MGR_USERNAME_PROPERTY = "authentication.ldap.managerDn"
  157. SSL_TRUSTSTORE_PATH_PROPERTY = "ssl.trustStore.path"
  158. SSL_TRUSTSTORE_PASSWORD_PROPERTY = "ssl.trustStore.password"
  159. SSL_TRUSTSTORE_TYPE_PROPERTY = "ssl.trustStore.type"
  160. AMBARI_CONF_VAR="AMBARI_CONF_DIR"
  161. AMBARI_SERVER_LIB="AMBARI_SERVER_LIB"
  162. JAVA_HOME="JAVA_HOME"
  163. PID_DIR="/var/run/ambari-server"
  164. BOOTSTRAP_DIR_PROPERTY="bootstrap.dir"
  165. PID_NAME="ambari-server.pid"
  166. AMBARI_PROPERTIES_FILE="ambari.properties"
  167. AMBARI_PROPERTIES_RPMSAVE_FILE="ambari.properties.rpmsave"
  168. RESOURCES_DIR_PROPERTY="resources.dir"
  169. SETUP_DB_CMD = ['su', '-', 'postgres',
  170. '--command=psql -f {0} -v username=\'"{1}"\' -v password="\'{2}\'"']
  171. UPGRADE_STACK_CMD = ['su', 'postgres',
  172. '--command=psql -f {0} -v stack_name="\'{1}\'" -v stack_version="\'{2}\'"']
  173. UPDATE_METAINFO_CMD = 'curl -X PUT "http://{0}:{1}/api/v1/stacks2" -u "{2}":"{3}"'
  174. PG_ST_CMD = "/sbin/service postgresql status"
  175. PG_INITDB_CMD = "/sbin/service postgresql initdb"
  176. PG_START_CMD = "/sbin/service postgresql start"
  177. PG_RESTART_CMD = "/sbin/service postgresql restart"
  178. PG_STATUS_RUNNING = "running"
  179. PG_HBA_DIR = "/var/lib/pgsql/data/"
  180. PG_HBA_CONF_FILE = PG_HBA_DIR + "pg_hba.conf"
  181. PG_HBA_CONF_FILE_BACKUP = PG_HBA_DIR + "pg_hba_bak.conf.old"
  182. POSTGRESQL_CONF_FILE = PG_HBA_DIR + "postgresql.conf"
  183. PG_HBA_RELOAD_CMD = "su postgres --command='pg_ctl -D {0} reload'"
  184. PG_DEFAULT_PASSWORD = "bigdata"
  185. JDBC_DATABASE_PROPERTY = "server.jdbc.database"
  186. JDBC_HOSTNAME_PROPERTY = "server.jdbc.hostname"
  187. JDBC_PORT_PROPERTY = "server.jdbc.port"
  188. JDBC_SCHEMA_PROPERTY = "server.jdbc.schema"
  189. JDBC_USER_NAME_PROPERTY = "server.jdbc.user.name"
  190. JDBC_PASSWORD_PROPERTY = "server.jdbc.user.passwd"
  191. JDBC_PASSWORD_FILENAME = "password.dat"
  192. JDBC_RCA_PASSWORD_FILENAME = "rca_password.dat"
  193. CLIENT_API_PORT_PROPERTY = "client.api.port"
  194. CLIENT_API_PORT = "8080"
  195. PERSISTENCE_TYPE_PROPERTY = "server.persistence.type"
  196. JDBC_DRIVER_PROPERTY = "server.jdbc.driver"
  197. JDBC_URL_PROPERTY = "server.jdbc.url"
  198. JDBC_RCA_DATABASE_PROPERTY = "server.jdbc.database"
  199. JDBC_RCA_HOSTNAME_PROPERTY = "server.jdbc.hostname"
  200. JDBC_RCA_PORT_PROPERTY = "server.jdbc.port"
  201. JDBC_RCA_SCHEMA_PROPERTY = "server.jdbc.schema"
  202. JDBC_RCA_DRIVER_PROPERTY = "server.jdbc.rca.driver"
  203. JDBC_RCA_URL_PROPERTY = "server.jdbc.rca.url"
  204. JDBC_RCA_USER_NAME_PROPERTY = "server.jdbc.rca.user.name"
  205. JDBC_RCA_PASSWORD_FILE_PROPERTY = "server.jdbc.rca.user.passwd"
  206. CHECK_COMMAND_EXIST_CMD = "type {0}"
  207. DATABASE_INDEX = 0
  208. PROMPT_DATABASE_OPTIONS = False
  209. USERNAME_PATTERN = "^[a-zA-Z_][a-zA-Z0-9_\-]*$"
  210. PASSWORD_PATTERN = "^[a-zA-Z0-9_-]*$"
  211. DATABASE_NAMES =["postgres", "oracle"]
  212. DATABASE_STORAGE_NAMES =["Database","Service","Schema"]
  213. DATABASE_PORTS =["5432", "1521", "3306"]
  214. DATABASE_DRIVER_NAMES = ["org.postgresql.Driver", "oracle.jdbc.driver.OracleDriver", "com.mysql.jdbc.Driver"]
  215. DATABASE_CONNECTION_STRINGS = [
  216. "jdbc:postgresql://{0}:{1}/{2}",
  217. "jdbc:oracle:thin:@{0}:{1}/{2}",
  218. "jdbc:mysql://{0}:{1}/{2}"]
  219. DATABASE_CONNECTION_STRINGS_ALT = [
  220. "jdbc:postgresql://{0}:{1}/{2}",
  221. "jdbc:oracle:thin:@{0}:{1}:{2}",
  222. "jdbc:mysql://{0}:{1}/{2}"]
  223. DATABASE_CLI_TOOLS = [["psql"], ["sqlplus", "sqlplus64"], ["mysql"]]
  224. DATABASE_CLI_TOOLS_DESC = ["psql", "sqlplus", "mysql"]
  225. DATABASE_CLI_TOOLS_USAGE = ['su -postgres --command=psql -f {0} -v username=\'"{1}"\' -v password="\'{2}\'"',
  226. 'sqlplus {1}/{2} < {0} ',
  227. 'mysql --user={1} --password={2} {3}<{0}']
  228. DATABASE_INIT_SCRIPTS = ['/var/lib/ambari-server/resources/Ambari-DDL-Postgres-REMOTE-CREATE.sql',
  229. '/var/lib/ambari-server/resources/Ambari-DDL-Oracle-CREATE.sql',
  230. '/var/lib/ambari-server/resources/Ambari-DDL-MySQL-CREATE.sql']
  231. DATABASE_DROP_SCRIPTS = ['/var/lib/ambari-server/resources/Ambari-DDL-Postgres-REMOTE-DROP.sql',
  232. '/var/lib/ambari-server/resources/Ambari-DDL-Oracle-DROP.sql',
  233. '/var/lib/ambari-server/resources/Ambari-DDL-MySQL-DROP.sql']
  234. REGEX_IP_ADDRESS = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"
  235. REGEX_HOSTNAME = "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$"
  236. REGEX_HOSTNAME_PORT = "^(.*:[0-9]{1,5}$)"
  237. REGEX_TRUE_FALSE = "^(true|false)?$"
  238. REGEX_ANYTHING = ".*"
  239. POSTGRES_EXEC_ARGS = "-h {0} -p {1} -d {2} -U {3} -f {4} -v username='\"{3}\"'"
  240. ORACLE_EXEC_ARGS = "-S '{0}/{1}@(description=(address=(protocol=TCP)(host={2})(port={3}))(connect_data=(sid={4})))' @{5} {0}"
  241. MYSQL_EXEC_ARGS = "--host={0} --port={1} --user={2} --password={3} {4} " \
  242. "-e\"set @schema=\'{4}\'; set @username=\'{2}\'; source {5};\""
  243. JDBC_PATTERNS = {"oracle":"*ojdbc*.jar", "mysql":"*mysql*.jar"}
  244. DATABASE_FULL_NAMES = {"oracle":"Oracle", "mysql":"MySQL", "postgres":"PostgreSQL"}
  245. ORACLE_DB_ID_TYPES = ["Service Name", "Service ID"]
  246. # jdk commands
  247. JDK_LOCAL_FILENAME = "jdk-6u31-linux-x64.bin"
  248. JDK_MIN_FILESIZE = 5000
  249. JDK_INSTALL_DIR = "/usr/jdk64"
  250. CREATE_JDK_DIR_CMD = "/bin/mkdir -p " + JDK_INSTALL_DIR
  251. MAKE_FILE_EXECUTABLE_CMD = "chmod a+x {0}"
  252. JAVA_HOME_PROPERTY = "java.home"
  253. JDK_URL_PROPERTY='jdk.url'
  254. JCE_URL_PROPERTY='jce_policy.url'
  255. OS_TYPE_PROPERTY = "server.os_type"
  256. GET_FQDN_SERVICE_URL="agent.fqdn.service.url"
  257. JDK_DOWNLOAD_CMD = "curl --create-dirs -o {0} {1}"
  258. JDK_DOWNLOAD_SIZE_CMD = "curl -I {0}"
  259. #JCE Policy files
  260. JCE_POLICY_FILENAME = "jce_policy-6.zip"
  261. JCE_DOWNLOAD_CMD = "curl -o {0} {1}"
  262. JCE_MIN_FILESIZE = 5000
  263. #Apache License Header
  264. ASF_LICENSE_HEADER = '''
  265. # Copyright 2011 The Apache Software Foundation
  266. #
  267. # Licensed to the Apache Software Foundation (ASF) under one
  268. # or more contributor license agreements. See the NOTICE file
  269. # distributed with this work for additional information
  270. # regarding copyright ownership. The ASF licenses this file
  271. # to you under the Apache License, Version 2.0 (the
  272. # "License"); you may not use this file except in compliance
  273. # with the License. You may obtain a copy of the License at
  274. #
  275. # http://www.apache.org/licenses/LICENSE-2.0
  276. #
  277. # Unless required by applicable law or agreed to in writing, software
  278. # distributed under the License is distributed on an "AS IS" BASIS,
  279. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  280. # See the License for the specific language governing permissions and
  281. # limitations under the License.
  282. '''
  283. def get_conf_dir():
  284. try:
  285. conf_dir = os.environ[AMBARI_CONF_VAR]
  286. return conf_dir
  287. except KeyError:
  288. default_conf_dir = "/etc/ambari-server/conf"
  289. print AMBARI_CONF_VAR + " is not set, using default " + default_conf_dir
  290. return default_conf_dir
  291. def find_properties_file():
  292. conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
  293. if conf_file is None:
  294. err = 'File %s not found in search path $%s: %s' % (AMBARI_PROPERTIES_FILE,
  295. AMBARI_CONF_VAR, get_conf_dir())
  296. print err
  297. raise FatalException(1, err)
  298. else:
  299. print_info_msg ('Loading properties from ' + conf_file)
  300. return conf_file
  301. def update_ambari_properties():
  302. prev_conf_file = search_file(AMBARI_PROPERTIES_RPMSAVE_FILE, get_conf_dir())
  303. conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
  304. # Previous config file does not exist
  305. if (not prev_conf_file) or (prev_conf_file is None):
  306. print_warning_msg("Can not find ambari.properties.rpmsave file from previous version, skipping import of settings")
  307. return 0
  308. try:
  309. old_properties = Properties()
  310. old_properties.load(open(prev_conf_file))
  311. except Exception, e:
  312. print 'Could not read "%s": %s' % (prev_conf_file, e)
  313. return -1
  314. try:
  315. new_properties = Properties()
  316. new_properties.load(open(conf_file))
  317. for prop_key, prop_value in old_properties.getPropertyDict().items():
  318. new_properties.process_pair(prop_key,prop_value)
  319. # Adding custom user name property if it is absent
  320. # In previous versions without custom user support server was started as
  321. # "root" anyway so it's a reasonable default
  322. if not NR_USER_PROPERTY in new_properties.keys():
  323. new_properties.process_pair(NR_USER_PROPERTY, "root")
  324. new_properties.store(open(conf_file,'w'))
  325. except Exception, e:
  326. print 'Could not write "%s": %s' % (conf_file, e)
  327. return -1
  328. timestamp = datetime.datetime.now()
  329. format = '%Y%m%d%H%M%S'
  330. os.rename(prev_conf_file, prev_conf_file + '.' + timestamp.strftime(format))
  331. return 0
  332. NR_CONF_DIR = get_conf_dir()
  333. # ownership/permissions mapping
  334. # path - permissions - user - group - recursive
  335. # Rules are executed in the same order as they are listed
  336. # {0} in user/group will be replaced by customized ambari-server username
  337. NR_ADJUST_OWNERSHIP_LIST =[
  338. ( "/var/log/ambari-server", "644", "{0}", True ),
  339. ( "/var/log/ambari-server", "755", "{0}", False ),
  340. ( "/var/run/ambari-server", "644", "{0}", True),
  341. ( "/var/run/ambari-server", "755", "{0}", False),
  342. ( "/var/run/ambari-server/bootstrap", "755", "{0}", False ),
  343. ( "/var/lib/ambari-server/ambari-env.sh", "700", "{0}", False ),
  344. ( "/var/lib/ambari-server/keys", "600", "{0}", True ),
  345. ( "/var/lib/ambari-server/keys", "700", "{0}", False ),
  346. ( "/var/lib/ambari-server/keys/db", "700", "{0}", False ),
  347. ( "/var/lib/ambari-server/keys/db/newcerts", "700", "{0}", False ),
  348. ( "/var/lib/ambari-server/keys/.ssh", "700", "{0}", False ),
  349. ( "/etc/ambari-server/conf", "644", "{0}", True ),
  350. ( "/etc/ambari-server/conf", "755", "{0}", False ),
  351. ( "/etc/ambari-server/conf/password.dat", "640", "{0}", False ),
  352. # Also, /etc/ambari-server/conf/password.dat
  353. # is generated later at store_password_file
  354. ]
  355. ### System interaction ###
  356. class FatalException(Exception):
  357. def __init__(self, code, reason):
  358. self.code = code
  359. self.reason = reason
  360. def __str__(self):
  361. return repr("Fatal exception: %s, exit code %s" % (self.reason, self.code))
  362. def _get_message(self):
  363. return str(self)
  364. class NonFatalException(Exception):
  365. def __init__(self, reason):
  366. self.reason = reason
  367. def __str__(self):
  368. return repr("NonFatal exception: %s" % self.reason)
  369. def _get_message(self):
  370. return str(self)
  371. def is_root():
  372. '''
  373. Checks effective UUID
  374. Returns True if a program is running under root-level privileges.
  375. '''
  376. return os.geteuid() == 0
  377. def get_exec_path(cmd):
  378. cmd = 'which {0}'.format(cmd)
  379. ret, out, err = run_in_shell(cmd)
  380. if ret == 0:
  381. return out.strip()
  382. else:
  383. return None
  384. def run_in_shell(cmd):
  385. print_info_msg('about to run command: ' + str(cmd))
  386. process = subprocess.Popen(cmd,
  387. stdout=subprocess.PIPE,
  388. stdin=subprocess.PIPE,
  389. stderr=subprocess.PIPE,
  390. shell=True
  391. )
  392. (stdoutdata, stderrdata) = process.communicate()
  393. return process.returncode, stdoutdata, stderrdata
  394. def run_os_command(cmd):
  395. print_info_msg('about to run command: ' + str(cmd))
  396. if type(cmd) == str:
  397. cmd = shlex.split(cmd)
  398. process = subprocess.Popen(cmd,
  399. stdout=subprocess.PIPE,
  400. stdin=subprocess.PIPE,
  401. stderr=subprocess.PIPE
  402. )
  403. (stdoutdata, stderrdata) = process.communicate()
  404. return process.returncode, stdoutdata, stderrdata
  405. #
  406. # Updates metainfo information from stack root. Re-cache information from
  407. # repoinfo.xml , metainfo.xml files , etc.
  408. #
  409. def update_metainfo(args):
  410. configure_update_metainfo_args(args)
  411. hostname = args.hostname
  412. port = args.port
  413. username = args.username
  414. password = args.password
  415. command = UPDATE_METAINFO_CMD
  416. command = command.format(hostname, port, username, password)
  417. retcode, outdata, errdata = run_os_command(command)
  418. if outdata.find("Bad credentials") > 0:
  419. print 'Incorrect credential provided. Please try again.'
  420. if not retcode == 0:
  421. print errdata
  422. return retcode
  423. def configure_update_metainfo_args(args):
  424. conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
  425. properties = Properties()
  426. try:
  427. properties.load(open(conf_file))
  428. except Exception, e:
  429. print 'Could not read ambari config file "%s": %s' % (conf_file, e)
  430. return -1
  431. default_username = "admin"
  432. username_prompt = 'Username [' + default_username + ']: '
  433. password_prompt = 'Password: '
  434. input_pattern = "^[a-zA-Z_][a-zA-Z0-9_\-]*$"
  435. hostname = socket.gethostname()
  436. port = properties[CLIENT_API_PORT_PROPERTY]
  437. if not port:
  438. port = CLIENT_API_PORT
  439. input_descr = "Invalid characters in received. Start with _ or alpha "\
  440. "followed by alphanumeric or _ or - characters"
  441. print 'Full authentication is required to access the Ambari API'
  442. username = get_validated_string_input(username_prompt, default_username,
  443. input_pattern, input_descr, False)
  444. password = get_validated_string_input(password_prompt, "", input_pattern,
  445. input_descr, True)
  446. args.hostname = hostname
  447. args.port = port
  448. args.username = username
  449. args.password = password
  450. #
  451. # Checks SELinux
  452. #
  453. def check_selinux():
  454. try:
  455. retcode, out, err = run_os_command(GET_SE_LINUX_ST_CMD)
  456. se_status = re.search('(disabled|enabled)', out).group(0)
  457. print "SELinux status is '" + se_status + "'"
  458. if se_status == SE_STATUS_DISABLED:
  459. return 0
  460. else:
  461. try:
  462. se_mode = re.search('(enforcing|permissive)', out).group(0)
  463. except AttributeError:
  464. err = "Error determining SELinux mode. Exiting."
  465. raise FatalException(1, err)
  466. print "SELinux mode is '" + se_mode + "'"
  467. if se_mode == SE_MODE_ENFORCING:
  468. print "Temporarily disabling SELinux"
  469. run_os_command(SE_SETENFORCE_CMD)
  470. print_warning_msg(
  471. "SELinux is set to 'permissive' mode and temporarily disabled.")
  472. ok = get_YN_input("OK to continue [y/n] (y)? ", True)
  473. if not ok:
  474. raise FatalException(1, None)
  475. return 0
  476. except OSError:
  477. print_warning_msg("Could not run {0}: OK".format(GET_SE_LINUX_ST_CMD))
  478. return 0
  479. def read_ambari_user():
  480. '''
  481. Reads ambari user from properties file
  482. '''
  483. conf_file = find_properties_file()
  484. try:
  485. properties = Properties()
  486. properties.load(open(conf_file))
  487. user = properties[NR_USER_PROPERTY]
  488. if user:
  489. return user
  490. else:
  491. return None
  492. except Exception, e:
  493. print_error_msg('Could not read "%s": %s' % (conf_file, e))
  494. return None
  495. def adjust_directory_permissions(ambari_user):
  496. properties = get_ambari_properties()
  497. bootstrap_dir = get_value_from_properties(properties, BOOTSTRAP_DIR_PROPERTY)
  498. print "Cleaning bootstrap directory ({0}) contents...".format(bootstrap_dir)
  499. cmd = RECURSIVE_RM_CMD.format(bootstrap_dir)
  500. run_os_command(cmd)
  501. os.mkdir(bootstrap_dir)
  502. # Add master key and credential store if exists
  503. keyLocation = get_master_key_location(properties)
  504. masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
  505. if masterKeyFile:
  506. NR_ADJUST_OWNERSHIP_LIST.append((masterKeyFile, "600", "{0}", "{0}", False))
  507. credStoreFile = get_credential_store_location(properties)
  508. if os.path.exists(credStoreFile):
  509. NR_ADJUST_OWNERSHIP_LIST.append((credStoreFile, "600", "{0}", "{0}", False))
  510. print "Adjusting ambari-server permissions and ownership..."
  511. for pack in NR_ADJUST_OWNERSHIP_LIST:
  512. file = pack[0]
  513. mod = pack[1]
  514. user = pack[2].format(ambari_user)
  515. recursive = pack[3]
  516. set_file_permissions(file, mod, user, recursive)
  517. def set_file_permissions(file, mod, user, recursive):
  518. WARN_MSG = "Command {0} returned exit code {1} with message: {2}"
  519. if recursive:
  520. params = " -R "
  521. else:
  522. params = ""
  523. if os.path.exists(file):
  524. command = NR_CHMOD_CMD.format(params, mod, file)
  525. retcode, out, err = run_os_command(command)
  526. if retcode != 0 :
  527. print_warning_msg(WARN_MSG.format(command, file, err))
  528. command = NR_CHOWN_CMD.format(params, user, file)
  529. retcode, out, err = run_os_command(command)
  530. if retcode != 0 :
  531. print_warning_msg(WARN_MSG.format(command, file, err))
  532. else:
  533. print_info_msg("File %s does not exist" % file)
  534. def create_custom_user():
  535. user = get_validated_string_input(
  536. "Enter user account for ambari-server daemon (root):",
  537. "root",
  538. "^[a-z_][a-z0-9_-]{1,31}$",
  539. "Invalid username.",
  540. False
  541. )
  542. print_info_msg("Trying to create user {0}".format(user))
  543. command = NR_USERADD_CMD.format(user, NR_USER_COMMENT)
  544. retcode, out, err = run_os_command(command)
  545. if retcode == 9: # 9 = username already in use
  546. print_info_msg("User {0} already exists, "
  547. "skipping user creation".format(user))
  548. elif retcode != 0: # fail
  549. print_warning_msg("Can't create user {0}. Command {1} "
  550. "finished with {2}: \n{3}".format(user, command, retcode, err))
  551. return retcode, None
  552. print_info_msg("User configuration is done.")
  553. return 0, user
  554. def check_ambari_user():
  555. try:
  556. user = read_ambari_user()
  557. create_user = False
  558. update_user_setting = False
  559. if user is not None:
  560. create_user = get_YN_input("Ambari-server daemon is configured to run under user '{0}'."
  561. " Change this setting [y/n] (n)? ".format(user), False)
  562. update_user_setting = create_user # Only if we will create another user
  563. else: # user is not configured yet
  564. update_user_setting = True # Write configuration anyway
  565. create_user = get_YN_input("Customize user account for ambari-server "
  566. "daemon [y/n] (n)? ", False)
  567. if not create_user:
  568. user = "root"
  569. if create_user:
  570. (retcode, user) = create_custom_user()
  571. if retcode != 0:
  572. return retcode
  573. if update_user_setting:
  574. write_property(NR_USER_PROPERTY, user)
  575. adjust_directory_permissions(user)
  576. except OSError:
  577. print_error_msg("Failed: %s" % OSError.message)
  578. return 4
  579. except Exception as e:
  580. print_error_msg("Unexpected error %s" % e.message)
  581. return 1
  582. return 0
  583. #
  584. # Checks iptables
  585. #
  586. def check_iptables():
  587. # not used
  588. # retcode, out, err = run_os_command(IP_TBLS_ST_CMD)
  589. ''' This check doesn't work on CentOS 6.2 if firewall AND
  590. iptables service are running if out == IP_TBLS_ENABLED:
  591. print 'iptables is enabled now'
  592. print 'Stopping iptables service'
  593. '''
  594. retcode, out, err = run_os_command(IP_TBLS_STOP_CMD)
  595. print 'iptables is disabled now. please reenable later.'
  596. if not retcode == 0 and err and len(err) > 0:
  597. print err
  598. if err.strip() == IP_TBLS_SRVC_NT_FND:
  599. return 0
  600. else:
  601. return retcode, out
  602. ### Postgres ###
  603. def configure_pg_hba_ambaridb_users():
  604. args = optparse.Values()
  605. configure_database_username_password(args)
  606. with open(PG_HBA_CONF_FILE, "a") as pgHbaConf:
  607. pgHbaConf.write("\n")
  608. pgHbaConf.write("local all " + args.database_username +
  609. ",mapred md5")
  610. pgHbaConf.write("\n")
  611. pgHbaConf.write("host all " + args.database_username +
  612. ",mapred 0.0.0.0/0 md5")
  613. pgHbaConf.write("\n")
  614. pgHbaConf.write("host all " + args.database_username +
  615. ",mapred ::/0 md5")
  616. pgHbaConf.write("\n")
  617. command = PG_HBA_RELOAD_CMD.format(PG_HBA_DIR)
  618. retcode, out, err = run_os_command(command)
  619. if not retcode == 0:
  620. raise FatalException(retcode, err)
  621. def configure_pg_hba_postgres_user():
  622. postgresString = "all postgres"
  623. for line in fileinput.input(PG_HBA_CONF_FILE, inplace=1):
  624. print re.sub('all\s*all', postgresString, line),
  625. os.chmod(PG_HBA_CONF_FILE, 0644)
  626. def configure_postgresql_conf():
  627. listenAddress = "listen_addresses = '*' #"
  628. for line in fileinput.input(POSTGRESQL_CONF_FILE, inplace=1):
  629. print re.sub('#+listen_addresses.*?(#|$)', listenAddress, line),
  630. os.chmod(POSTGRESQL_CONF_FILE, 0644)
  631. def configure_postgres():
  632. if os.path.isfile(PG_HBA_CONF_FILE):
  633. if not os.path.isfile(PG_HBA_CONF_FILE_BACKUP):
  634. shutil.copyfile(PG_HBA_CONF_FILE, PG_HBA_CONF_FILE_BACKUP)
  635. else:
  636. #Postgres has been configured before, must not override backup
  637. print "Backup for pg_hba found, reconfiguration not required"
  638. return 0
  639. configure_pg_hba_postgres_user()
  640. configure_pg_hba_ambaridb_users()
  641. os.chmod(PG_HBA_CONF_FILE, 0644)
  642. configure_postgresql_conf()
  643. #restart postgresql if already running
  644. pg_status = get_postgre_status()
  645. if pg_status == PG_STATUS_RUNNING:
  646. retcode = restart_postgres()
  647. return retcode
  648. return 0
  649. def restart_postgres():
  650. print "Restarting PostgreSQL"
  651. process = subprocess.Popen(PG_RESTART_CMD.split(' '),
  652. stdout=subprocess.PIPE,
  653. stdin=subprocess.PIPE,
  654. stderr=subprocess.PIPE
  655. )
  656. time.sleep(5)
  657. result = process.poll()
  658. if result is None:
  659. print_info_msg("Killing restart PostgresSQL process")
  660. process.kill()
  661. pg_status = get_postgre_status()
  662. # SUSE linux set status of stopped postgresql proc to unused
  663. if pg_status == "unused" or pg_status == "stopped":
  664. print_info_msg("PostgreSQL is stopped. Restarting ...")
  665. retcode, out, err = run_os_command(PG_START_CMD)
  666. return retcode
  667. return 0
  668. # todo: check if the scheme is already exist
  669. def write_property(key, value):
  670. conf_file = find_properties_file()
  671. properties = Properties()
  672. try:
  673. properties.load(open(conf_file))
  674. except Exception, e:
  675. print_error_msg('Could not read ambari config file "%s": %s' % (conf_file, e))
  676. return -1
  677. properties.process_pair(key, value)
  678. try:
  679. properties.store(open(conf_file, "w"))
  680. except Exception, e:
  681. print_error_msg('Could not write ambari config file "%s": %s' % (conf_file, e))
  682. return -1
  683. return 0
  684. def setup_db(args):
  685. #password access to ambari-server and mapred
  686. configure_database_username_password(args)
  687. dbname = args.database_name
  688. scriptFile = args.init_script_file
  689. username = args.database_username
  690. password = args.database_password
  691. command = SETUP_DB_CMD[:]
  692. command[-1] = command[-1].format(scriptFile, username, password)
  693. retcode, outdata, errdata = run_os_command(command)
  694. if not retcode == 0:
  695. print errdata
  696. return retcode
  697. def store_password_file(password, filename):
  698. conf_file = find_properties_file()
  699. passFilePath = os.path.join(os.path.dirname(conf_file),
  700. filename)
  701. with open(passFilePath, 'w+') as passFile:
  702. passFile.write(password)
  703. print_info_msg("Adjusting filesystem permissions")
  704. ambari_user = read_ambari_user()
  705. set_file_permissions(passFilePath, "660", ambari_user, False)
  706. return passFilePath
  707. def remove_password_file(filename):
  708. conf_file = find_properties_file()
  709. passFilePath = os.path.join(os.path.dirname(conf_file),
  710. filename)
  711. if os.path.exists(passFilePath):
  712. try:
  713. os.remove(passFilePath)
  714. except Exception, e:
  715. print_warning_msg('Unable to remove password file: ' + str(e))
  716. return 1
  717. pass
  718. return 0
  719. def execute_db_script(args, file):
  720. #password access to ambari-server and mapred
  721. configure_database_username_password(args)
  722. dbname = args.database_name
  723. username = args.database_username
  724. password = args.database_password
  725. command = SETUP_DB_CMD[:]
  726. command[-1] = command[-1].format(file, username, password)
  727. retcode, outdata, errdata = run_os_command(command)
  728. if not retcode == 0:
  729. print errdata
  730. return retcode
  731. def check_db_consistency(args, file):
  732. #password access to ambari-server and mapred
  733. configure_database_username_password(args)
  734. dbname = args.database_name
  735. username = args.database_username
  736. password = args.database_password
  737. command = SETUP_DB_CMD[:]
  738. command[-1] = command[-1].format(file, username, password)
  739. retcode, outdata, errdata = run_os_command(command)
  740. if not retcode == 0:
  741. print errdata
  742. return retcode
  743. else:
  744. # Assumes that the output is of the form ...\n<count>
  745. print_info_msg("Parsing output: " + outdata)
  746. lines = outdata.splitlines()
  747. if (lines[-1] == '3' or lines[-1] == '0'):
  748. return 0
  749. return -1
  750. def get_postgre_status():
  751. retcode, out, err = run_os_command(PG_ST_CMD)
  752. try:
  753. pg_status = re.search('(stopped|running)', out).group(0)
  754. except AttributeError:
  755. pg_status = None
  756. return pg_status
  757. def check_postgre_up():
  758. pg_status = get_postgre_status()
  759. if pg_status == PG_STATUS_RUNNING:
  760. print_info_msg ("PostgreSQL is running")
  761. return 0
  762. else:
  763. print "Running initdb: This may take upto a minute."
  764. retcode, out, err = run_os_command(PG_INITDB_CMD)
  765. if retcode == 0:
  766. print out
  767. print "About to start PostgreSQL"
  768. try:
  769. process = subprocess.Popen(PG_START_CMD.split(' '),
  770. stdout=subprocess.PIPE,
  771. stdin=subprocess.PIPE,
  772. stderr=subprocess.PIPE
  773. )
  774. time.sleep(20)
  775. result = process.poll()
  776. print_info_msg("Result of postgres start cmd: " + str(result))
  777. if result is None:
  778. process.kill()
  779. pg_status = get_postgre_status()
  780. if pg_status == PG_STATUS_RUNNING:
  781. print_info_msg("Postgres process is running. Returning...")
  782. return 0
  783. else:
  784. retcode = result
  785. except (Exception), e:
  786. pg_status = get_postgre_status()
  787. if pg_status == PG_STATUS_RUNNING:
  788. return 0
  789. else:
  790. print_error_msg("Postgres start failed. " + str(e))
  791. return 1
  792. return retcode
  793. def get_validated_db_name(database_name):
  794. return get_validated_string_input(
  795. DATABASE_STORAGE_NAMES[DATABASE_INDEX] + " Name ["
  796. + database_name + "]:",
  797. database_name,
  798. ".*",
  799. "Invalid " + DATABASE_STORAGE_NAMES[DATABASE_INDEX] + " name.",
  800. False
  801. )
  802. def get_validated_service_name(service_name, index):
  803. return get_validated_string_input(
  804. ORACLE_DB_ID_TYPES[index] + " [" + service_name + "]:",
  805. service_name,
  806. ".*",
  807. "Invalid " + ORACLE_DB_ID_TYPES[index] + ".",
  808. False
  809. )
  810. def read_password(passwordDefault=PG_DEFAULT_PASSWORD,
  811. passwordPattern=PASSWORD_PATTERN,
  812. passwordPrompt=None,
  813. passwordDescr=None):
  814. # setup password
  815. if passwordPrompt is None:
  816. passwordPrompt = 'Password [' + passwordDefault + ']: '
  817. if passwordDescr is None:
  818. passwordDescr = "Invalid characters in password. Use only alphanumeric or " \
  819. "_ or - characters"
  820. password = get_validated_string_input(passwordPrompt, passwordDefault,
  821. passwordPattern, passwordDescr, True)
  822. if not password:
  823. print 'Password cannot be blank.'
  824. read_password(passwordDefault, passwordPattern, passwordPrompt, passwordDescr)
  825. if password != passwordDefault:
  826. password1 = get_validated_string_input("Re-enter password: ",
  827. passwordDefault, passwordPattern, passwordDescr, True)
  828. if password != password1:
  829. print "Passwords do not match"
  830. password = read_password(passwordDefault, passwordPattern, passwordPrompt, passwordDescr)
  831. return password
  832. def get_pass_file_path(conf_file):
  833. return os.path.join(os.path.dirname(conf_file),
  834. JDBC_PASSWORD_FILENAME)
  835. # Set database properties to default values
  836. def load_default_db_properties(args):
  837. args.database=DATABASE_NAMES[DATABASE_INDEX]
  838. args.database_host = "localhost"
  839. args.database_port = DATABASE_PORTS[DATABASE_INDEX]
  840. args.database_name = "ambari"
  841. args.database_username = "ambari"
  842. args.database_password = "bigdata"
  843. args.sid_or_sname = "sname"
  844. pass
  845. # Ask user for database conenction properties
  846. def prompt_db_properties(args):
  847. global DATABASE_INDEX
  848. if PROMPT_DATABASE_OPTIONS:
  849. load_default_db_properties(args)
  850. ok = get_YN_input("Enter advanced database configuration [y/n] (n)? ", False)
  851. if ok:
  852. database_num = str(DATABASE_INDEX + 1)
  853. database_num = get_validated_string_input(
  854. "Select database:\n1 - Postgres(Embedded)\n2 - Oracle\n[" + database_num + "]:",
  855. database_num,
  856. "^[12]$",
  857. "Invalid number.",
  858. False
  859. )
  860. DATABASE_INDEX = int(database_num) - 1
  861. args.database = DATABASE_NAMES[DATABASE_INDEX]
  862. if args.database != "postgres" :
  863. args.database_host = get_validated_string_input(
  864. "Hostname [" + args.database_host + "]:",
  865. args.database_host,
  866. "^[a-zA-Z0-9.\-]*$",
  867. "Invalid hostname.",
  868. False
  869. )
  870. args.database_port=DATABASE_PORTS[DATABASE_INDEX]
  871. args.database_port = get_validated_string_input(
  872. "Port [" + args.database_port + "]:",
  873. args.database_port,
  874. "^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$",
  875. "Invalid port.",
  876. False
  877. )
  878. if args.database == "oracle":
  879. # Oracle uses service name or service id
  880. idType = "1"
  881. idType = get_validated_string_input(
  882. "Select type of id to use:\n1 - " + ORACLE_DB_ID_TYPES[0] +
  883. "\n2 - " + ORACLE_DB_ID_TYPES[1] + "\n[" + idType + "]:",
  884. idType,
  885. "^[12]$",
  886. "Invalid number.",
  887. False
  888. )
  889. if idType == "2":
  890. args.sid_or_sname = "sid"
  891. IDTYPE_INDEX = int(idType) - 1
  892. args.database_name = get_validated_service_name(args.database_name,
  893. IDTYPE_INDEX)
  894. else:
  895. # MySQL and other DB types
  896. pass
  897. pass
  898. else:
  899. args.database_host = "localhost"
  900. args.database_port = DATABASE_PORTS[DATABASE_INDEX]
  901. args.database_name = get_validated_db_name(args.database_name)
  902. pass
  903. # Username is common for Oracle/MySQL/Postgres
  904. args.database_username = get_validated_string_input(
  905. 'Username [' + args.database_username + ']: ',
  906. args.database_username,
  907. USERNAME_PATTERN,
  908. "Invalid characters in username. Start with _ or alpha "
  909. "followed by alphanumeric or _ or - characters",
  910. False
  911. )
  912. args.database_password = configure_database_password(True)
  913. print_info_msg('Using database options: {database},{host},{port},{schema},{user},{password}'.format(
  914. database=args.database,
  915. host=args.database_host,
  916. port=args.database_port,
  917. schema=args.database_name,
  918. user=args.database_username,
  919. password=args.database_password
  920. ))
  921. # Store set of properties for remote database connection
  922. def store_remote_properties(args):
  923. properties = get_ambari_properties()
  924. if properties == -1:
  925. print_error_msg ("Error getting ambari properties")
  926. return -1
  927. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  928. if isSecure and isSecure.lower() == 'true':
  929. isSecure = True
  930. else:
  931. isSecure = False
  932. properties.process_pair(PERSISTENCE_TYPE_PROPERTY, "remote")
  933. properties.process_pair(JDBC_DATABASE_PROPERTY, args.database)
  934. properties.process_pair(JDBC_HOSTNAME_PROPERTY, args.database_host)
  935. properties.process_pair(JDBC_PORT_PROPERTY, args.database_port)
  936. properties.process_pair(JDBC_SCHEMA_PROPERTY, args.database_name)
  937. properties.process_pair(JDBC_DRIVER_PROPERTY, DATABASE_DRIVER_NAMES[DATABASE_INDEX])
  938. # fully qualify the hostname to make sure all the other hosts can connect
  939. # to the jdbc hostname since its passed onto the agents for RCA
  940. jdbc_hostname = args.database_host
  941. if (args.database_host == "localhost"):
  942. jdbc_hostname = socket.getfqdn();
  943. connectionStringFormat = DATABASE_CONNECTION_STRINGS
  944. if args.sid_or_sname == "sid":
  945. connectionStringFormat = DATABASE_CONNECTION_STRINGS_ALT
  946. properties.process_pair(JDBC_URL_PROPERTY, connectionStringFormat[DATABASE_INDEX].format(jdbc_hostname, args.database_port, args.database_name))
  947. properties.process_pair(JDBC_USER_NAME_PROPERTY, args.database_username)
  948. if isSecure:
  949. properties.process_pair(JDBC_PASSWORD_PROPERTY,
  950. encrypt_password(JDBC_RCA_PASSWORD_ALIAS, args.database_password))
  951. else:
  952. properties.process_pair(JDBC_PASSWORD_PROPERTY,
  953. store_password_file(args.database_password, JDBC_PASSWORD_FILENAME))
  954. properties.process_pair(JDBC_RCA_DRIVER_PROPERTY, DATABASE_DRIVER_NAMES[DATABASE_INDEX])
  955. properties.process_pair(JDBC_RCA_URL_PROPERTY, connectionStringFormat[DATABASE_INDEX].format(jdbc_hostname, args.database_port, args.database_name))
  956. properties.process_pair(JDBC_RCA_USER_NAME_PROPERTY, args.database_username)
  957. if isSecure:
  958. properties.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY,
  959. encrypt_password(JDBC_RCA_PASSWORD_ALIAS, args.database_password))
  960. else:
  961. properties.process_pair(JDBC_RCA_PASSWORD_FILE_PROPERTY,
  962. store_password_file(args.database_password, JDBC_PASSWORD_FILENAME))
  963. conf_file = properties.fileName
  964. try:
  965. properties.store(open(conf_file, "w"))
  966. except Exception, e:
  967. print 'Could not write ambari config file "%s": %s' % (conf_file, e)
  968. return -1
  969. return 0
  970. # Initialize remote database schema
  971. def setup_remote_db(args):
  972. not_found_msg = "Cannot find {0} {1} client in the path to load the Ambari Server schema.\
  973. Before starting Ambari Server, you must run the following DDL against the database to create \
  974. the schema ".format(DATABASE_NAMES[DATABASE_INDEX], str(DATABASE_CLI_TOOLS_DESC[DATABASE_INDEX]))
  975. client_usage_cmd = DATABASE_CLI_TOOLS_USAGE[DATABASE_INDEX].format(DATABASE_INIT_SCRIPTS[DATABASE_INDEX], args.database_username,
  976. args.database_password, args.database_name)
  977. retcode, out, err = execute_remote_script(args, DATABASE_INIT_SCRIPTS[DATABASE_INDEX])
  978. if retcode != 0:
  979. if retcode == -1:
  980. print_warning_msg(not_found_msg + os.linesep + client_usage_cmd)
  981. if not SILENT:
  982. raw_input(PRESS_ENTER_MSG)
  983. return retcode
  984. print err
  985. print_error_msg('Database bootstrap failed. Please, provide correct connection properties.')
  986. return retcode
  987. return 0
  988. # Get database client executable path
  989. def get_db_cli_tool(args):
  990. for tool in DATABASE_CLI_TOOLS[DATABASE_INDEX]:
  991. cmd =CHECK_COMMAND_EXIST_CMD.format(tool)
  992. ret, out, err = run_in_shell(cmd)
  993. if ret == 0:
  994. return get_exec_path(tool)
  995. return None
  996. #execute SQL script on remote database
  997. def execute_remote_script(args, scriptPath):
  998. tool = get_db_cli_tool(args)
  999. if not tool:
  1000. args.warnings.append('{0} not found. Please, run DDL script manually'.format(DATABASE_CLI_TOOLS[DATABASE_INDEX]))
  1001. if VERBOSE:
  1002. print_warning_msg('{0} not found'.format(DATABASE_CLI_TOOLS[DATABASE_INDEX]))
  1003. return -1, "Client wasn't found", "Client wasn't found"
  1004. if args.database == "postgres":
  1005. os.environ["PGPASSWORD"] = args.database_password
  1006. retcode, out, err = run_in_shell('{0} {1}'.format(tool, POSTGRES_EXEC_ARGS.format(
  1007. args.database_host,
  1008. args.database_port,
  1009. args.database_name,
  1010. args.database_username,
  1011. scriptPath
  1012. )))
  1013. return retcode, out, err
  1014. elif args.database == "oracle":
  1015. retcode, out, err = run_in_shell('{0} {1}'.format(tool, ORACLE_EXEC_ARGS.format(
  1016. args.database_username,
  1017. args.database_password,
  1018. args.database_host,
  1019. args.database_port,
  1020. args.database_name,
  1021. scriptPath
  1022. )))
  1023. return retcode, out, err
  1024. elif args.database=="mysql":
  1025. retcode, out, err = run_in_shell('{0} {1}'.format(tool, MYSQL_EXEC_ARGS.format(
  1026. args.database_host,
  1027. args.database_port,
  1028. args.database_username,
  1029. args.database_password,
  1030. args.database_name,
  1031. scriptPath
  1032. )))
  1033. return retcode, out, err
  1034. return -2, "Wrong database", "Wrong database"
  1035. def configure_database_password(showDefault=True):
  1036. passwordDefault = PG_DEFAULT_PASSWORD
  1037. if showDefault:
  1038. passwordPrompt = 'Enter Database Password [' + passwordDefault + ']: '
  1039. else:
  1040. passwordPrompt = 'Enter Database Password: '
  1041. passwordPattern = "^[a-zA-Z0-9_-]*$"
  1042. passwordDescr = "Invalid characters in password. Use only alphanumeric or "\
  1043. "_ or - characters"
  1044. password = read_password(passwordDefault, passwordPattern, passwordPrompt,
  1045. passwordDescr)
  1046. return password
  1047. def configure_database_username_password(args):
  1048. properties = get_ambari_properties()
  1049. if properties == -1:
  1050. print_error_msg ("Error getting ambari properties")
  1051. return -1
  1052. username = properties[JDBC_USER_NAME_PROPERTY]
  1053. passwordProp = properties[JDBC_PASSWORD_PROPERTY]
  1054. if username and passwordProp:
  1055. print_info_msg("Database username + password already configured")
  1056. args.database_username=username
  1057. if is_alias_string(passwordProp):
  1058. args.database_password = decrypt_password_for_alias(JDBC_RCA_PASSWORD_ALIAS)
  1059. else:
  1060. if os.path.exists(passwordProp):
  1061. with open(passwordProp, 'r') as file:
  1062. args.database_password = file.read()
  1063. return 1
  1064. else:
  1065. print_error_msg("Connection properties not set in config file.")
  1066. # Store local database connection properties
  1067. def store_local_properties(args):
  1068. properties = get_ambari_properties()
  1069. if properties == -1:
  1070. print_error_msg ("Error getting ambari properties")
  1071. return -1
  1072. properties.removeOldProp(JDBC_SCHEMA_PROPERTY)
  1073. properties.removeOldProp(JDBC_HOSTNAME_PROPERTY)
  1074. properties.removeOldProp(JDBC_DATABASE_PROPERTY)
  1075. properties.removeOldProp(JDBC_RCA_DRIVER_PROPERTY)
  1076. properties.removeOldProp(JDBC_RCA_URL_PROPERTY)
  1077. properties.removeOldProp(JDBC_PORT_PROPERTY)
  1078. properties.removeOldProp(JDBC_PORT_PROPERTY)
  1079. properties.removeOldProp(JDBC_DRIVER_PROPERTY)
  1080. properties.removeOldProp(JDBC_URL_PROPERTY)
  1081. properties.removeOldProp(JDBC_DATABASE_PROPERTY)
  1082. properties.process_pair(PERSISTENCE_TYPE_PROPERTY, "local")
  1083. properties.process_pair(JDBC_USER_NAME_PROPERTY, args.database_username)
  1084. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  1085. if isSecure and isSecure.lower() == 'true':
  1086. properties.process_pair(JDBC_PASSWORD_PROPERTY,
  1087. encrypt_password(JDBC_RCA_PASSWORD_ALIAS, args.database_password))
  1088. else:
  1089. properties.process_pair(JDBC_PASSWORD_PROPERTY,
  1090. store_password_file(args.database_password, JDBC_PASSWORD_FILENAME))
  1091. conf_file = properties.fileName
  1092. try:
  1093. properties.store(open(conf_file, "w"))
  1094. except Exception, e:
  1095. print 'Could not write ambari config file "%s": %s' % (conf_file, e)
  1096. return -1
  1097. return 0
  1098. # Load ambari properties and return dict with values
  1099. def get_ambari_properties():
  1100. conf_file = find_properties_file()
  1101. properties = None
  1102. try:
  1103. properties = Properties()
  1104. properties.load(open(conf_file))
  1105. except (Exception), e:
  1106. print 'Could not read "%s": %s' % (conf_file, e)
  1107. return -1
  1108. return properties
  1109. # Load database connection properties from conf file
  1110. def parse_properties_file(args):
  1111. properties = get_ambari_properties()
  1112. if properties == -1:
  1113. print_error_msg ("Error getting ambari properties")
  1114. return -1
  1115. args.persistence_type = properties[PERSISTENCE_TYPE_PROPERTY]
  1116. if not args.persistence_type:
  1117. args.persistence_type = "local"
  1118. if args.persistence_type == 'remote':
  1119. args.database = properties[JDBC_DATABASE_PROPERTY]
  1120. args.database_host = properties[JDBC_HOSTNAME_PROPERTY]
  1121. args.database_port = properties[JDBC_PORT_PROPERTY]
  1122. args.database_name = properties[JDBC_SCHEMA_PROPERTY]
  1123. global DATABASE_INDEX
  1124. try:
  1125. DATABASE_INDEX = DATABASE_NAMES.index(args.database)
  1126. except ValueError:
  1127. pass
  1128. args.database_username = properties[JDBC_USER_NAME_PROPERTY]
  1129. args.database_password_file = properties[JDBC_PASSWORD_PROPERTY]
  1130. if args.database_password_file:
  1131. if not is_alias_string(args.database_password_file):
  1132. args.database_password = open(properties[JDBC_PASSWORD_PROPERTY]).read()
  1133. else:
  1134. args.database_password = args.database_password_file
  1135. return 0
  1136. ### JDK ###
  1137. def get_ambari_jars():
  1138. try:
  1139. conf_dir = os.environ[AMBARI_SERVER_LIB]
  1140. return conf_dir
  1141. except KeyError:
  1142. default_jar_location = "/usr/lib/ambari-server"
  1143. print_info_msg(AMBARI_SERVER_LIB + " is not set, using default "
  1144. + default_jar_location)
  1145. return default_jar_location
  1146. def get_share_jars():
  1147. share_jars = ""
  1148. file_list = []
  1149. file_list.extend(glob.glob(JAVA_SHARE_PATH + os.sep + "*mysql*"))
  1150. file_list.extend(glob.glob(JAVA_SHARE_PATH + os.sep + "*ojdbc*"))
  1151. if len(file_list) > 0:
  1152. share_jars = string.join(file_list, os.pathsep)
  1153. return share_jars
  1154. def get_ambari_classpath():
  1155. ambari_cp = get_ambari_jars() + os.sep + "*"
  1156. share_cp = get_share_jars()
  1157. if len(share_cp) > 0:
  1158. ambari_cp = ambari_cp + os.pathsep + share_cp
  1159. return ambari_cp
  1160. def search_file(filename, search_path, pathsep=os.pathsep):
  1161. """ Given a search path, find file with requested name """
  1162. for path in string.split(search_path, pathsep):
  1163. candidate = os.path.join(path, filename)
  1164. if os.path.exists(candidate): return os.path.abspath(candidate)
  1165. return None
  1166. def dlprogress(base_name, count, blockSize, totalSize):
  1167. percent = int(count * blockSize * 100 / totalSize)
  1168. if (totalSize < blockSize):
  1169. sys.stdout.write("\r" + base_name + "... %d%%" % (100))
  1170. else:
  1171. sys.stdout.write("\r" + base_name + "... %d%% (%.1f MB of %.1f MB)" % (
  1172. percent, count * blockSize / 1024 / 1024.0, totalSize / 1024 / 1024.0))
  1173. if (percent == 100 or totalSize < blockSize):
  1174. sys.stdout.write("\n")
  1175. sys.stdout.flush()
  1176. def track_jdk(base_name, url, local_name):
  1177. u = urllib2.urlopen(url)
  1178. h = u.info()
  1179. totalSize = int(h["Content-Length"])
  1180. fp = open(local_name, "wb")
  1181. blockSize = 8192
  1182. count = 0
  1183. percent = 0
  1184. while True:
  1185. chunk = u.read(blockSize)
  1186. if not chunk:
  1187. break
  1188. fp.write(chunk)
  1189. count += 1
  1190. dlprogress(base_name, count, blockSize, totalSize)
  1191. fp.flush()
  1192. fp.close()
  1193. def install_jce_manualy(args):
  1194. properties = get_ambari_properties()
  1195. if properties == -1:
  1196. err = "Error getting ambari properties"
  1197. raise FatalException(-1, err)
  1198. if args.jce_policy and os.path.exists(args.jce_policy):
  1199. jce_destination = os.path.join(properties[RESOURCES_DIR_PROPERTY], JCE_POLICY_FILENAME)
  1200. shutil.copy(args.jce_policy, jce_destination)
  1201. print "JCE policy copied from " + args.jce_policy + " to " + jce_destination
  1202. return 0
  1203. else:
  1204. return 1
  1205. #
  1206. # Downloads the JDK
  1207. #
  1208. def download_jdk(args):
  1209. jce_installed = install_jce_manualy(args)
  1210. properties = get_ambari_properties()
  1211. if properties == -1:
  1212. err = "Error getting ambari properties"
  1213. raise FatalException(-1, err)
  1214. conf_file = properties.fileName
  1215. ok = False
  1216. if get_JAVA_HOME():
  1217. pass # do nothing
  1218. elif args.java_home and os.path.exists(args.java_home):
  1219. print_warning_msg("JAVA_HOME " + args.java_home
  1220. + " must be valid on ALL hosts")
  1221. write_property(JAVA_HOME_PROPERTY, args.java_home)
  1222. else:
  1223. try:
  1224. jdk_url = properties[JDK_URL_PROPERTY]
  1225. resources_dir = properties[RESOURCES_DIR_PROPERTY]
  1226. except (KeyError), e:
  1227. err = 'Property ' + str(e) + ' is not defined at ' + conf_file
  1228. raise FatalException(1, err)
  1229. dest_file = resources_dir + os.sep + JDK_LOCAL_FILENAME
  1230. if os.path.exists(dest_file):
  1231. print "JDK already exists, using " + dest_file
  1232. elif args.jdk_location and os.path.exists(args.jdk_location):
  1233. print "Copying local JDK file {0} to {1}".format(args.jdk_location, dest_file)
  1234. try:
  1235. shutil.copyfile(args.jdk_location, dest_file)
  1236. except Exception, e:
  1237. err = "Can not copy file {0} to {1} due to: {2} . Please check file " \
  1238. "permissions and free disk space.".format(args.jdk_location,
  1239. dest_file, e.message)
  1240. raise FatalException(1, err)
  1241. else:
  1242. print 'Downloading JDK from ' + jdk_url + ' to ' + dest_file
  1243. jdk_download_fail_msg = " Failed to download JDK: {0}. Please check that Oracle " \
  1244. "JDK is available at {1}. Also you may specify JDK file " \
  1245. "location in local filesystem using --jdk-location command " \
  1246. "line argument.".format("{0}", jdk_url)
  1247. try:
  1248. size_command = JDK_DOWNLOAD_SIZE_CMD.format(jdk_url);
  1249. #Get Header from url,to get file size then
  1250. retcode, out, err = run_os_command(size_command)
  1251. if out.find("Content-Length") == -1:
  1252. err = jdk_download_fail_msg.format("Request header doesn't contain Content-Length")
  1253. raise FatalException(1, err)
  1254. start_with = int(out.find("Content-Length") + len("Content-Length") + 2)
  1255. end_with = out.find("\r\n", start_with)
  1256. src_size = int(out[start_with:end_with])
  1257. print 'JDK distribution size is ' + str(src_size) + ' bytes'
  1258. file_exists = os.path.isfile(dest_file)
  1259. file_size = -1
  1260. if file_exists:
  1261. file_size = os.stat(dest_file).st_size
  1262. if file_exists and file_size == src_size:
  1263. print_info_msg("File already exists")
  1264. else:
  1265. track_jdk(JDK_LOCAL_FILENAME, jdk_url, dest_file)
  1266. print 'Successfully downloaded JDK distribution to ' + dest_file
  1267. except FatalException:
  1268. raise
  1269. except Exception, e:
  1270. err = jdk_download_fail_msg.format(str(e))
  1271. raise FatalException(1, err)
  1272. downloaded_size = os.stat(dest_file).st_size
  1273. if downloaded_size != src_size or downloaded_size < JDK_MIN_FILESIZE:
  1274. err = 'Size of downloaded JDK distribution file is ' \
  1275. + str(downloaded_size) + ' bytes, it is probably \
  1276. damaged or incomplete'
  1277. raise FatalException(1, err)
  1278. try:
  1279. out, ok = install_jdk(dest_file)
  1280. jdk_version = re.search('Creating (jdk.*)/jre', out).group(1)
  1281. except Exception, e:
  1282. print "Installation of JDK has failed: %s\n" % e.message
  1283. file_exists = os.path.isfile(dest_file)
  1284. if file_exists:
  1285. ok = get_YN_input("JDK found at "+dest_file+". "
  1286. "Would you like to re-download the JDK [y/n] (y)? ", True)
  1287. if not ok:
  1288. err = "Unable to install JDK. Please remove JDK file found at "+ \
  1289. dest_file +" and re-run Ambari Server setup"
  1290. raise FatalException(1, err)
  1291. else:
  1292. track_jdk(JDK_LOCAL_FILENAME, jdk_url, dest_file)
  1293. print 'Successfully re-downloaded JDK distribution to ' + dest_file
  1294. try:
  1295. out, ok = install_jdk(dest_file)
  1296. jdk_version = re.search('Creating (jdk.*)/jre', out).group(1)
  1297. except Exception, e:
  1298. print "Installation of JDK was failed: %s\n" % e.message
  1299. err = "Unable to install JDK. Please remove JDK, file found at "+ \
  1300. dest_file +" and re-run Ambari Server setup"
  1301. raise FatalException(1, err)
  1302. else:
  1303. err = "Unable to install JDK. File "+ dest_file +" does not exist, " \
  1304. "please re-run Ambari Server setup"
  1305. raise FatalException(1, err)
  1306. print "Successfully installed JDK to {0}/{1}".\
  1307. format(JDK_INSTALL_DIR, jdk_version)
  1308. write_property(JAVA_HOME_PROPERTY, "{0}/{1}".
  1309. format(JDK_INSTALL_DIR, jdk_version))
  1310. if jce_installed != 0:
  1311. try:
  1312. download_jce_policy(properties, ok)
  1313. except FatalException as e:
  1314. print "JCE Policy files are required for secure HDP setup. Please ensure " \
  1315. " all hosts have the JCE unlimited strength policy 6, files."
  1316. print_error_msg("Failed to download JCE policy files:")
  1317. if e.reason is not None:
  1318. print_error_msg("Reason: {0}".format(e.reason))
  1319. # TODO: We don't fail installation if download_jce_policy fails. Is it OK?
  1320. return 0
  1321. def download_jce_policy(properties, accpeted_bcl):
  1322. try:
  1323. jce_url = properties[JCE_URL_PROPERTY]
  1324. resources_dir = properties[RESOURCES_DIR_PROPERTY]
  1325. except KeyError, e:
  1326. err = 'Property ' + str(e) + ' is not defined in properties file'
  1327. raise FatalException(1, err)
  1328. dest_file = resources_dir + os.sep + JCE_POLICY_FILENAME
  1329. if not os.path.exists(dest_file):
  1330. print 'Downloading JCE Policy archive from ' + jce_url + ' to ' + dest_file
  1331. jce_download_fail_msg = " Failed to download JCE Policy archive : {0}. " \
  1332. "Please check that JCE Policy archive is available " \
  1333. "at {1} . Also you may install JCE Policy archive manually using " \
  1334. "--jce-policy command line argument.".format("{0}", jce_url)
  1335. try:
  1336. size_command = JDK_DOWNLOAD_SIZE_CMD.format(jce_url);
  1337. #Get Header from url,to get file size then
  1338. retcode, out, err = run_os_command(size_command)
  1339. if out.find("Content-Length") == -1:
  1340. err = jce_download_fail_msg.format(
  1341. "Request header doesn't contain Content-Length")
  1342. raise FatalException(1, err)
  1343. start_with = int(out.find("Content-Length") + len("Content-Length") + 2)
  1344. end_with = out.find("\r\n", start_with)
  1345. src_size = int(out[start_with:end_with])
  1346. print_info_msg('JCE zip distribution size is ' + str(src_size) + ' bytes')
  1347. file_exists = os.path.isfile(dest_file)
  1348. file_size = -1
  1349. if file_exists:
  1350. file_size = os.stat(dest_file).st_size
  1351. if file_exists and file_size == src_size:
  1352. print_info_msg("File already exists")
  1353. else:
  1354. #BCL license before download
  1355. jce_download_cmd = JCE_DOWNLOAD_CMD.format(dest_file, jce_url)
  1356. print_info_msg("JCE download cmd: " + jce_download_cmd)
  1357. if accpeted_bcl:
  1358. retcode, out, err = run_os_command(jce_download_cmd)
  1359. if retcode == 0:
  1360. print 'Successfully downloaded JCE Policy archive to ' + dest_file
  1361. else:
  1362. raise FatalException(1, err)
  1363. else:
  1364. ok = get_YN_input("To download the JCE Policy archive you must "
  1365. "accept the license terms found at "
  1366. "http://www.oracle.com/technetwork/java/javase"
  1367. "/terms/license/index.html"
  1368. "Not accepting might result in failure when "
  1369. "setting up HDP security. \nDo you accept the "
  1370. "Oracle Binary Code License Agreement [y/n] (y)? ", True)
  1371. if ok:
  1372. retcode, out, err = run_os_command(jce_download_cmd)
  1373. if retcode == 0:
  1374. print 'Successfully downloaded JCE Policy archive to ' + dest_file
  1375. else:
  1376. raise FatalException(1, None)
  1377. except FatalException:
  1378. raise
  1379. except Exception, e:
  1380. err = 'Failed to download JCE Policy archive: ' + str(e)
  1381. raise FatalException(1, err)
  1382. downloaded_size = os.stat(dest_file).st_size
  1383. if downloaded_size != src_size or downloaded_size < JCE_MIN_FILESIZE:
  1384. err = 'Size of downloaded JCE Policy archive is ' \
  1385. + str(downloaded_size) + ' bytes, it is probably \
  1386. damaged or incomplete'
  1387. raise FatalException(1, err)
  1388. else:
  1389. print "JCE Policy archive already exists, using " + dest_file
  1390. class RetCodeException(Exception): pass
  1391. def install_jdk(dest_file):
  1392. ok = get_YN_input("To install the Oracle JDK you must accept the "
  1393. "license terms found at "
  1394. "http://www.oracle.com/technetwork/java/javase/"
  1395. "downloads/jdk-6u21-license-159167.txt. Not accepting will "
  1396. "cancel the Ambari Server setup.\nDo you accept the "
  1397. "Oracle Binary Code License Agreement [y/n] (y)? ", True)
  1398. if not ok:
  1399. raise FatalException(1, None)
  1400. print "Installing JDK to {0}".format(JDK_INSTALL_DIR)
  1401. retcode, out, err = run_os_command(CREATE_JDK_DIR_CMD)
  1402. savedPath = os.getcwd()
  1403. os.chdir(JDK_INSTALL_DIR)
  1404. retcode, out, err = run_os_command(MAKE_FILE_EXECUTABLE_CMD.format(dest_file))
  1405. retcode, out, err = run_os_command(dest_file + ' -noregister')
  1406. os.chdir(savedPath)
  1407. if retcode != 0:
  1408. err = "Installation of JDK returned exit code %s" % retcode
  1409. raise FatalException(retcode, err)
  1410. return out, ok
  1411. #
  1412. # Configures the OS settings in ambari properties.
  1413. #
  1414. def configure_os_settings():
  1415. properties = get_ambari_properties()
  1416. if properties == -1:
  1417. print_error_msg ("Error getting ambari properties")
  1418. return -1
  1419. try:
  1420. conf_os_type = properties[OS_TYPE_PROPERTY]
  1421. if conf_os_type != '':
  1422. print_info_msg ("os_type already setting in properties file")
  1423. return 0
  1424. except (KeyError), e:
  1425. print_error_msg ("os_type is not set in properties file")
  1426. os_system = platform.system()
  1427. if os_system != 'Linux':
  1428. print_error_msg ("Non-Linux systems are not supported")
  1429. return -1
  1430. os_info = platform.linux_distribution(
  1431. None, None, None, ['SuSE', 'redhat' ], 0
  1432. )
  1433. os_name = os_info[0].lower()
  1434. if os_name == 'suse':
  1435. os_name = 'sles'
  1436. os_version = os_info[1].split('.', 1)[0]
  1437. master_os_type = os_name + os_version
  1438. write_property(OS_TYPE_PROPERTY, master_os_type)
  1439. return 0
  1440. def get_JAVA_HOME():
  1441. properties = get_ambari_properties()
  1442. if properties == -1:
  1443. print_error_msg ("Error getting ambari properties")
  1444. return None
  1445. java_home = properties[JAVA_HOME_PROPERTY]
  1446. if (not 0 == len(java_home)) and (os.path.exists(java_home)):
  1447. return java_home
  1448. return None
  1449. #
  1450. # Finds the available JDKs.
  1451. #
  1452. def find_jdk():
  1453. if get_JAVA_HOME():
  1454. return get_JAVA_HOME()
  1455. print "Looking for available JDKs at " + JDK_INSTALL_DIR
  1456. jdks = glob.glob(JDK_INSTALL_DIR + os.sep + "jdk*")
  1457. jdks.sort()
  1458. print "Found: " + str(jdks)
  1459. count = len(jdks)
  1460. if count == 0:
  1461. return
  1462. jdkPath = jdks[count - 1]
  1463. print "Selected JDK {0}".format(jdkPath)
  1464. return jdkPath
  1465. #
  1466. # Checks if options determine local DB configuration
  1467. #
  1468. def is_local_database(options):
  1469. if options.database == DATABASE_NAMES[0] \
  1470. and options.database_host == "localhost" \
  1471. and options.database_port == DATABASE_PORTS[0] \
  1472. and options.database_name == "ambari":
  1473. return True
  1474. return False
  1475. #Check if required jdbc drivers present
  1476. def find_jdbc_driver(args):
  1477. if args.database in JDBC_PATTERNS.keys():
  1478. drivers = []
  1479. drivers.extend(glob.glob(JAVA_SHARE_PATH + os.sep + JDBC_PATTERNS[args.database]))
  1480. if drivers:
  1481. return drivers
  1482. return -1
  1483. return 0
  1484. def copy_files(files, dest_dir):
  1485. if os.path.isdir(dest_dir):
  1486. for filepath in files:
  1487. shutil.copy(filepath, dest_dir)
  1488. return 0
  1489. else:
  1490. return -1
  1491. def check_jdbc_drivers(args):
  1492. properties = get_ambari_properties()
  1493. if properties == -1:
  1494. print_error_msg ("Error getting ambari properties")
  1495. return -1
  1496. result = find_jdbc_driver(args)
  1497. msg = 'Before starting Ambari Server, ' \
  1498. 'you must copy the {0} JDBC driver JAR file to {1}.'.format(
  1499. DATABASE_FULL_NAMES[args.database],
  1500. JAVA_SHARE_PATH)
  1501. if result == -1:
  1502. if SILENT:
  1503. print_error_msg(msg)
  1504. raise FatalException(-1, msg)
  1505. else:
  1506. print_warning_msg(msg)
  1507. raw_input(PRESS_ENTER_MSG)
  1508. result = find_jdbc_driver(args)
  1509. if result == -1:
  1510. print_error_msg(msg)
  1511. raise FatalException(-1, msg)
  1512. # Check if selected RDBMS requires drivers to copy
  1513. if type(result) is not int:
  1514. print 'Copying JDBC drivers to server resources...'
  1515. try:
  1516. resources_dir = properties[RESOURCES_DIR_PROPERTY]
  1517. except KeyError:
  1518. print_error_msg("There is no value for " + RESOURCES_DIR_PROPERTY + "in " + AMBARI_PROPERTIES_FILE)
  1519. return -1
  1520. copy_status = copy_files(result, resources_dir)
  1521. if not copy_status == 0:
  1522. raise FatalException(-1, "Failed to copy JDBC drivers to server resources")
  1523. return 0
  1524. #
  1525. # Setup the Ambari Server.
  1526. #
  1527. def setup(args):
  1528. if not is_root():
  1529. err = 'Ambari-server setup should be run with '\
  1530. 'root-level privileges'
  1531. raise FatalException(4, err)
  1532. print 'Checking SELinux...'
  1533. retcode = check_selinux()
  1534. if not retcode == 0:
  1535. err = 'Failed to disable SELinux. Exiting.'
  1536. raise FatalException(retcode, err)
  1537. # Create ambari user, if needed
  1538. retcode = check_ambari_user()
  1539. if not retcode == 0:
  1540. err = 'Failed to create user. Exiting.'
  1541. raise FatalException(retcode, err)
  1542. print 'Checking iptables...'
  1543. retcode, out = check_iptables()
  1544. if not retcode == 0 and out == IP_TBLS_ENABLED:
  1545. err = 'Failed to stop iptables. Exiting.'
  1546. raise FatalException(retcode, err)
  1547. print 'Checking JDK...'
  1548. try:
  1549. download_jdk(args)
  1550. except FatalException as e:
  1551. err = 'Downloading or installing JDK failed: {0}. Exiting.'.format(e)
  1552. raise FatalException(e.code, err)
  1553. print 'Completing setup...'
  1554. retcode = configure_os_settings()
  1555. if not retcode == 0:
  1556. err = 'Configure of OS settings in ambari.properties failed. Exiting.'
  1557. raise FatalException(retcode, err)
  1558. print 'Configuring database...'
  1559. prompt_db_properties(args)
  1560. #DB setup should be done last after doing any setup.
  1561. if is_local_database(args):
  1562. print 'Default properties detected. Using built-in database.'
  1563. store_local_properties(args)
  1564. print 'Checking PostgreSQL...'
  1565. retcode = check_postgre_up()
  1566. if not retcode == 0:
  1567. err = 'Unable to start PostgreSQL server. Exiting'
  1568. raise FatalException(retcode, err)
  1569. print 'Configuring local database...'
  1570. retcode = setup_db(args)
  1571. if not retcode == 0:
  1572. err = 'Running database init script was failed. Exiting.'
  1573. raise FatalException(retcode, err)
  1574. print 'Configuring PostgreSQL...'
  1575. retcode = configure_postgres()
  1576. if not retcode == 0:
  1577. err = 'Unable to configure PostgreSQL server. Exiting'
  1578. raise FatalException(retcode, err)
  1579. else:
  1580. retcode = store_remote_properties(args)
  1581. if retcode != 0:
  1582. err = 'Unable to save config file'
  1583. raise FatalException(retcode, err)
  1584. check_jdbc_drivers(args)
  1585. print 'Configuring remote database connection properties...'
  1586. retcode = setup_remote_db(args)
  1587. if retcode == -1:
  1588. err = "The cli was not found"
  1589. raise NonFatalException(err)
  1590. if not retcode == 0:
  1591. err = 'Error while configuring connection properties. Exiting'
  1592. raise FatalException(retcode, err)
  1593. check_jdbc_drivers(args)
  1594. #
  1595. # Resets the Ambari Server.
  1596. #
  1597. def reset(args):
  1598. if not is_root():
  1599. err = 'Ambari-server reset should be run with ' \
  1600. 'root-level privileges'
  1601. raise FatalException(4, err)
  1602. choice = get_YN_input("**** WARNING **** You are about to reset and clear the "
  1603. "Ambari Server database. This will remove all cluster "
  1604. "host and configuration information from the database. "
  1605. "You will be required to re-configure the Ambari server "
  1606. "and re-run the cluster wizard. \n"
  1607. "Are you SURE you want to perform the reset "
  1608. "[yes/no]? ", True)
  1609. okToRun = choice
  1610. if not okToRun:
  1611. err = "Ambari Server 'reset' cancelled"
  1612. raise FatalException(1, err)
  1613. okToRun = get_YN_input("Confirm server reset [yes/no]? ", True)
  1614. if not okToRun:
  1615. err = "Ambari Server 'reset' cancelled"
  1616. raise FatalException(1, err)
  1617. print "Resetting the Server database..."
  1618. parse_properties_file(args)
  1619. # configure_database_username_password(args)
  1620. if args.persistence_type=="remote":
  1621. client_desc = DATABASE_NAMES[DATABASE_INDEX] + ' ' + DATABASE_CLI_TOOLS_DESC[DATABASE_INDEX]
  1622. client_usage_cmd_drop = DATABASE_CLI_TOOLS_USAGE[DATABASE_INDEX].format(DATABASE_DROP_SCRIPTS[DATABASE_INDEX], args.database_username,
  1623. args.database_password, args.database_name)
  1624. client_usage_cmd_init = DATABASE_CLI_TOOLS_USAGE[DATABASE_INDEX].format(DATABASE_INIT_SCRIPTS[DATABASE_INDEX], args.database_username,
  1625. args.database_password, args.database_name)
  1626. if get_db_cli_tool(args) != -1:
  1627. retcode, out, err = execute_remote_script(args, DATABASE_DROP_SCRIPTS[DATABASE_INDEX])
  1628. if not retcode == 0:
  1629. if retcode == -1:
  1630. print_warning_msg('Cannot find ' + client_desc +
  1631. ' client in the path to reset the Ambari Server ' +
  1632. ' schema. To reset Ambari Server schema ' +
  1633. 'you must run the following DDL against the database ' +
  1634. 'to drop the schema:' + os.linesep + client_usage_cmd_drop
  1635. + os.linesep + ', then you must run the following DDL '
  1636. + 'against the database to create the schema ' + os.linesep
  1637. + client_usage_cmd_init + os.linesep )
  1638. raise NonFatalException(err)
  1639. retcode, out, err = execute_remote_script(args, DATABASE_INIT_SCRIPTS[DATABASE_INDEX])
  1640. if not retcode == 0:
  1641. if retcode == -1:
  1642. print_warning_msg('Cannot find ' + client_desc + ' client in the path to ' +
  1643. 'reset the Ambari Server schema. To reset Ambari Server schema ' +
  1644. 'you must run the following DDL against the database to '
  1645. + 'drop the schema:' + os.linesep + client_usage_cmd_drop
  1646. + os.linesep + ', then you must run the following DDL ' +
  1647. 'against the database to create the schema ' + os.linesep +
  1648. client_usage_cmd_init + os.linesep )
  1649. raise NonFatalException(err)
  1650. else:
  1651. err = 'Cannot find ' + client_desc + ' client in the path to reset the Ambari ' +\
  1652. 'Server schema. To reset Ambari Server schema ' + \
  1653. 'you must run the following DDL against the database to drop the schema:' + \
  1654. os.linesep + client_usage_cmd_drop + os.linesep + \
  1655. ', then you must run the following DDL against the database to create the ' + \
  1656. 'schema ' + os.linesep + client_usage_cmd_init + os.linesep
  1657. raise NonFatalException(err)
  1658. else:
  1659. dbname = args.database_name
  1660. filename = args.drop_script_file
  1661. username = args.database_username
  1662. password = args.database_password
  1663. command = SETUP_DB_CMD[:]
  1664. command[-1] = command[-1].format(filename, username, password)
  1665. retcode, outdata, errdata = run_os_command(command)
  1666. if not retcode == 0:
  1667. raise FatalException(1, errdata)
  1668. print_info_msg ("About to run database setup")
  1669. setup_db(args)
  1670. #
  1671. # Starts the Ambari Server.
  1672. #
  1673. def start(args):
  1674. current_user = getpass.getuser()
  1675. ambari_user = read_ambari_user()
  1676. if ambari_user is None:
  1677. err = "Can not detect a system user for Ambari. " \
  1678. "Please run \"setup\" command to create such user "
  1679. raise FatalException(1, err)
  1680. if current_user != ambari_user and not is_root():
  1681. err = "Can not start ambari-server as user {0}. Please either run \"start\" " \
  1682. "command as root or as user {1}".format(current_user, ambari_user)
  1683. raise FatalException(1, err)
  1684. parse_properties_file(args)
  1685. if os.path.exists(PID_DIR + os.sep + PID_NAME):
  1686. f = open(PID_DIR + os.sep + PID_NAME, "r")
  1687. pid = int(f.readline())
  1688. f.close()
  1689. try:
  1690. os.kill(pid, 0)
  1691. err = "Server is already running."
  1692. raise FatalException(1, err)
  1693. except OSError as e:
  1694. print_info_msg("Server is not running...")
  1695. conf_dir = get_conf_dir()
  1696. jdk_path = find_jdk()
  1697. if jdk_path is None:
  1698. err = "No JDK found, please run the \"setup\" " \
  1699. "command to install a JDK automatically or install any " \
  1700. "JDK manually to " + JDK_INSTALL_DIR
  1701. raise FatalException(1, err)
  1702. # Preparations
  1703. if is_root():
  1704. print "Have root privileges."
  1705. if args.persistence_type == "local":
  1706. retcode = check_postgre_up()
  1707. if not retcode == 0:
  1708. err = "Unable to start PostgreSQL server. Exiting"
  1709. raise FatalException(retcode, err)
  1710. print 'Checking iptables...'
  1711. retcode, out = check_iptables()
  1712. if not retcode == 0 and out == IP_TBLS_ENABLED:
  1713. err = "Failed to stop iptables. Exiting"
  1714. raise FatalException(retcode, err)
  1715. else: # Skipping actions that require root permissions
  1716. print "Can not check iptables status when starting "\
  1717. "without root privileges."
  1718. print "Please don't forget to disable or adjust iptables if needed"
  1719. if args.persistence_type == "local":
  1720. print "Can not check PostgreSQL server status when starting " \
  1721. "without root privileges."
  1722. print "Please don't forget to start PostgreSQL server."
  1723. properties = get_ambari_properties()
  1724. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  1725. isSecure = True if isSecure and isSecure.lower() == 'true' else False
  1726. keyLocation = get_master_key_location(properties)
  1727. masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
  1728. environ = os.environ.copy()
  1729. # Need to handle master key not persisted scenario
  1730. if isSecure and not masterKeyFile:
  1731. prompt = False
  1732. masterKey = environ.get(SECURITY_KEY_ENV_VAR_NAME)
  1733. if masterKey is not None and masterKey != "":
  1734. pass
  1735. else:
  1736. keyLocation = environ.get(SECURITY_MASTER_KEY_LOCATION)
  1737. if keyLocation is not None:
  1738. try:
  1739. # Verify master key can be read by the java process
  1740. with open(keyLocation, 'r') : pass
  1741. except IOError:
  1742. print_warning_msg("Cannot read Master key from path specified in "
  1743. "environemnt.")
  1744. prompt = True
  1745. else:
  1746. # Key not provided in the environment
  1747. prompt = True
  1748. if prompt:
  1749. masterKey = get_validated_string_input("Please provide master key " +\
  1750. "for unlocking credential store: ", "", ".*", "", True, False)
  1751. tempDir = tempfile.gettempdir()
  1752. tempFilePath = tempDir + os.sep + "masterkey"
  1753. save_master_key(masterKey, tempFilePath, True)
  1754. if ambari_user != current_user:
  1755. uid = pwd.getpwnam(ambari_user).pw_uid
  1756. gid = pwd.getpwnam(ambari_user).pw_gid
  1757. os.chown(tempFilePath, uid, gid)
  1758. else:
  1759. os.chmod(tempFilePath, stat.S_IREAD | stat.S_IWRITE)
  1760. if tempFilePath is not None:
  1761. environ[SECURITY_MASTER_KEY_LOCATION] = tempFilePath
  1762. pidfile = PID_DIR + os.sep + PID_NAME
  1763. command_base = SERVER_START_CMD_DEBUG if (SERVER_DEBUG_MODE or SERVER_START_DEBUG) else SERVER_START_CMD
  1764. command = command_base.format(jdk_path, conf_dir, get_ambari_classpath(), pidfile)
  1765. if is_root() and ambari_user != "root":
  1766. # To inherit exported environment variables (especially AMBARI_PASSPHRASE),
  1767. # from subprocess, we have to skip --login option of su command. That's why
  1768. # we change dir to / (otherwise subprocess can face with 'permission denied'
  1769. # errors while trying to list current directory
  1770. os.chdir("/")
  1771. param_list = ["/bin/su", ambari_user, "-s", "/bin/sh", "-c", command]
  1772. else:
  1773. param_list = ["/bin/sh", "-c", command]
  1774. print "Running server: " + str(param_list)
  1775. server_process = subprocess.Popen(param_list, env=environ)
  1776. #
  1777. # Stops the Ambari Server.
  1778. #
  1779. def stop(args):
  1780. if (args != None):
  1781. args.exit_message = None
  1782. if os.path.exists(PID_DIR + os.sep + PID_NAME):
  1783. f = open(PID_DIR + os.sep + PID_NAME, "r")
  1784. pid = int(f.readline())
  1785. try:
  1786. os.killpg(os.getpgid(pid), signal.SIGKILL)
  1787. except OSError, e:
  1788. print_info_msg( "Unable to stop Ambari Server - " + str(e) )
  1789. return
  1790. f.close()
  1791. os.remove(f.name)
  1792. print "Ambari Server stopped"
  1793. else:
  1794. print "Ambari Server is not running"
  1795. ### Stack upgrade ###
  1796. def upgrade_stack(args, stack_id):
  1797. if not is_root():
  1798. err = 'Ambari-server upgradestack should be run with ' \
  1799. 'root-level privileges'
  1800. raise FatalException(4, err)
  1801. #password access to ambari-server and mapred
  1802. configure_database_username_password(args)
  1803. dbname = args.database_name
  1804. file = args.upgrade_stack_script_file
  1805. stack_name, stack_version = stack_id.split(STACK_NAME_VER_SEP)
  1806. command = UPGRADE_STACK_CMD[:]
  1807. command[-1] = command[-1].format(file, stack_name, stack_version)
  1808. retcode, outdata, errdata = run_os_command(command)
  1809. if not retcode == 0:
  1810. raise FatalException(retcode, errdata)
  1811. return retcode
  1812. #
  1813. # Upgrades the Ambari Server.
  1814. #
  1815. def upgrade(args):
  1816. if not is_root():
  1817. err = 'Ambari-server upgrade should be run with ' \
  1818. 'root-level privileges'
  1819. raise FatalException(4, err)
  1820. print 'Updating properties in ' + AMBARI_PROPERTIES_FILE + ' ...'
  1821. retcode = update_ambari_properties()
  1822. if not retcode == 0:
  1823. err = AMBARI_PROPERTIES_FILE + ' file can\'t be updated. Exiting'
  1824. raise FatalException(retcode, err)
  1825. parse_properties_file(args)
  1826. if args.persistence_type == "remote":
  1827. pass
  1828. else:
  1829. print 'Checking PostgreSQL...'
  1830. retcode = check_postgre_up()
  1831. if not retcode == 0:
  1832. err = 'PostgreSQL server not running. Exiting'
  1833. raise FatalException(retcode, err)
  1834. file = args.upgrade_script_file
  1835. print 'Upgrading database...'
  1836. retcode = execute_db_script(args, file)
  1837. if not retcode == 0:
  1838. err = 'Database upgrade script has failed. Exiting.'
  1839. raise FatalException(retcode, err)
  1840. print 'Checking database integrity...'
  1841. check_file = file[:-3] + "Check" + file[-4:]
  1842. retcode = check_db_consistency(args, check_file)
  1843. if not retcode == 0:
  1844. print 'Found inconsistency. Trying to fix...'
  1845. fix_file = file[:-3] + "Fix" + file[-4:]
  1846. retcode = execute_db_script(args, fix_file)
  1847. if not retcode == 0:
  1848. err = 'Database cannot be fixed. Exiting.'
  1849. raise FatalException(retcode, err)
  1850. else:
  1851. print 'Database is consistent.'
  1852. user = read_ambari_user()
  1853. if user is None:
  1854. warn = 'Can not determine custom ambari user. Please run ' \
  1855. '"ambari-server setup" before starting server'
  1856. print_warning_msg(warn)
  1857. else:
  1858. adjust_directory_permissions(user)
  1859. #
  1860. # The Ambari Server status.
  1861. #
  1862. def status(args):
  1863. args.exit_message = None
  1864. status, pid = is_server_runing()
  1865. if status:
  1866. print "Ambari Server running"
  1867. print "Found Ambari Server PID: '" + str(pid) + " at: " + PID_DIR + os.sep + PID_NAME
  1868. else:
  1869. print "Ambari Server not running. Stale PID File at: " + PID_DIR + os.sep + PID_NAME
  1870. #
  1871. # Prints an "info" messsage.
  1872. #
  1873. def print_info_msg(msg):
  1874. if VERBOSE:
  1875. print("INFO: " + msg)
  1876. #
  1877. # Prints an "error" messsage.
  1878. #
  1879. def print_error_msg(msg):
  1880. print("ERROR: " + msg)
  1881. #
  1882. # Prints a "warning" messsage.
  1883. #
  1884. def print_warning_msg(msg, bold=False):
  1885. if bold:
  1886. print(BOLD_ON + "WARNING: " + msg + BOLD_OFF)
  1887. else:
  1888. print("WARNING: " + msg)
  1889. #
  1890. # Gets the y/n input.
  1891. #
  1892. # return True if 'y' or False if 'n'
  1893. #
  1894. def get_YN_input(prompt,default):
  1895. yes = set(['yes','ye', 'y'])
  1896. no = set(['no','n'])
  1897. return get_choice_string_input(prompt,default,yes,no)
  1898. def get_choice_string_input(prompt,default,firstChoice,secondChoice):
  1899. if SILENT:
  1900. print(prompt)
  1901. return default
  1902. choice = raw_input(prompt).lower()
  1903. if choice in firstChoice:
  1904. return True
  1905. elif choice in secondChoice:
  1906. return False
  1907. elif choice is "": # Just enter pressed
  1908. return default
  1909. else:
  1910. print "input not recognized, please try again: "
  1911. return get_choice_string_input(prompt,default,firstChoice,secondChoice)
  1912. def get_validated_string_input(prompt, default, pattern, description,
  1913. is_pass, allowEmpty=True):
  1914. input = ""
  1915. while not input:
  1916. if SILENT:
  1917. print (prompt)
  1918. input = default
  1919. elif is_pass:
  1920. input = getpass.getpass(prompt)
  1921. else:
  1922. input = raw_input(prompt)
  1923. if not input.strip():
  1924. # Empty input - if default available use default
  1925. if not allowEmpty and not default:
  1926. print 'Property cannot be blank.'
  1927. input = ""
  1928. continue
  1929. else:
  1930. input = default
  1931. break #done here and picking up default
  1932. else:
  1933. if not pattern==None and not re.search(pattern,input.strip()):
  1934. print description
  1935. input= ""
  1936. return input
  1937. def get_value_from_properties(properties, key, default=""):
  1938. try:
  1939. value = properties.get_property(key)
  1940. if not value:
  1941. value = default
  1942. except:
  1943. return default
  1944. return value
  1945. def get_prompt_default(defaultStr=None):
  1946. if not defaultStr or defaultStr == "":
  1947. return ""
  1948. else:
  1949. return '(' + defaultStr + ')'
  1950. def setup_ldap():
  1951. if not is_root():
  1952. err = 'Ambari-server setup-ldap should be run with ' \
  1953. 'root-level privileges'
  1954. raise FatalException(4, err)
  1955. properties = get_ambari_properties()
  1956. # python2.x dict is not ordered
  1957. ldap_property_list_reqd = ["authentication.ldap.primaryUrl",
  1958. "authentication.ldap.secondaryUrl",
  1959. "authentication.ldap.useSSL",
  1960. "authentication.ldap.usernameAttribute",
  1961. "authentication.ldap.baseDn",
  1962. "authentication.ldap.bindAnonymously" ]
  1963. ldap_property_list_opt = [ "authentication.ldap.managerDn",
  1964. LDAP_MGR_PASSWORD_PROPERTY,
  1965. SSL_TRUSTSTORE_TYPE_PROPERTY,
  1966. SSL_TRUSTSTORE_PATH_PROPERTY,
  1967. SSL_TRUSTSTORE_PASSWORD_PROPERTY]
  1968. ldap_property_list_truststore=[SSL_TRUSTSTORE_TYPE_PROPERTY,
  1969. SSL_TRUSTSTORE_PATH_PROPERTY,
  1970. SSL_TRUSTSTORE_PASSWORD_PROPERTY]
  1971. ldap_property_list_passwords=[LDAP_MGR_PASSWORD_PROPERTY,
  1972. SSL_TRUSTSTORE_PASSWORD_PROPERTY]
  1973. LDAP_PRIMARY_URL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[0])
  1974. LDAP_SECONDARY_URL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[1])
  1975. LDAP_USE_SSL_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[2], "false")
  1976. LDAP_USER_ATT_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[3], "uid")
  1977. LDAP_BASE_DN_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[4])
  1978. LDAP_BIND_DEFAULT = get_value_from_properties(properties, ldap_property_list_reqd[5], "false")
  1979. LDAP_MGR_DN_DEFAULT = get_value_from_properties(properties, ldap_property_list_opt[0])
  1980. SSL_TRUSTSTORE_TYPE_DEFAULT = get_value_from_properties(properties, SSL_TRUSTSTORE_TYPE_PROPERTY, "jks")
  1981. SSL_TRUSTSTORE_PATH_DEFAULT = get_value_from_properties(properties, SSL_TRUSTSTORE_PATH_PROPERTY)
  1982. ldap_properties_map_reqd =\
  1983. {
  1984. ldap_property_list_reqd[0]:(LDAP_PRIMARY_URL_DEFAULT, "Primary URL* {{host:port}} {0}: ".format(get_prompt_default(LDAP_PRIMARY_URL_DEFAULT)), False),\
  1985. ldap_property_list_reqd[1]:(LDAP_SECONDARY_URL_DEFAULT, "Secondary URL {0}: ".format(get_prompt_default(LDAP_SECONDARY_URL_DEFAULT)), True),\
  1986. ldap_property_list_reqd[2]:(LDAP_USE_SSL_DEFAULT, "Use SSL* [true/false] {0}: ".format(get_prompt_default(LDAP_USE_SSL_DEFAULT)), False),\
  1987. ldap_property_list_reqd[3]:(LDAP_USER_ATT_DEFAULT, "User name attribute* {0}: ".format(get_prompt_default(LDAP_USER_ATT_DEFAULT)), False),\
  1988. ldap_property_list_reqd[4]:(LDAP_BASE_DN_DEFAULT, "Base DN* {0}: ".format(get_prompt_default(LDAP_BASE_DN_DEFAULT)), False),\
  1989. ldap_property_list_reqd[5]:(LDAP_BIND_DEFAULT, "Bind anonymously* [true/false] {0}: ".format(get_prompt_default(LDAP_BIND_DEFAULT)), False)\
  1990. }
  1991. ldap_property_value_map = {}
  1992. for idx, key in enumerate(ldap_property_list_reqd):
  1993. if idx == 0:
  1994. pattern = REGEX_HOSTNAME_PORT
  1995. elif idx in [2, 5]:
  1996. pattern = REGEX_TRUE_FALSE
  1997. else:
  1998. pattern = REGEX_ANYTHING
  1999. input = get_validated_string_input(ldap_properties_map_reqd[key][1],
  2000. ldap_properties_map_reqd[key][0], pattern,
  2001. "Invalid characters in the input!", False, ldap_properties_map_reqd[key][2])
  2002. if input is not None and input != "":
  2003. ldap_property_value_map[key] = input
  2004. bindAnonymously = ldap_property_value_map["authentication.ldap.bindAnonymously"]
  2005. anonymous = (bindAnonymously and bindAnonymously.lower() == 'true')
  2006. password = None
  2007. # Ask for manager credentials only if bindAnonymously is false
  2008. if not anonymous:
  2009. username = get_validated_string_input("Manager DN* {0}: ".format(
  2010. get_prompt_default(LDAP_MGR_DN_DEFAULT)), LDAP_MGR_DN_DEFAULT, ".*",
  2011. "Invalid characters in the input!", False, False)
  2012. ldap_property_value_map[LDAP_MGR_USERNAME_PROPERTY] = username
  2013. password = configure_ldap_password()
  2014. ldap_property_value_map[LDAP_MGR_PASSWORD_PROPERTY] = password
  2015. useSSL = ldap_property_value_map["authentication.ldap.useSSL"]
  2016. ldaps = (useSSL and useSSL.lower() == 'true')
  2017. if ldaps:
  2018. truststore_default = "n"
  2019. truststore_set = bool(SSL_TRUSTSTORE_PATH_DEFAULT)
  2020. if truststore_set:
  2021. truststore_default = "y"
  2022. custom_trust_store = get_YN_input("Do you want to provide custom TrustStore for Ambari [y/n] ({0})?".
  2023. format(truststore_default),
  2024. truststore_set)
  2025. if custom_trust_store:
  2026. ts_type = get_validated_string_input(
  2027. "TrustStore type [jks/jceks/pkcs12] {0}:".format(get_prompt_default(SSL_TRUSTSTORE_TYPE_DEFAULT)),
  2028. SSL_TRUSTSTORE_TYPE_DEFAULT,
  2029. "^(jks|jceks|pkcs12)?$", "Wrong type", False)
  2030. ts_path = None
  2031. while not ts_path:
  2032. ts_path = get_validated_string_input(
  2033. "Path to TrustStore file {0}:".format(get_prompt_default(SSL_TRUSTSTORE_PATH_DEFAULT)),
  2034. SSL_TRUSTSTORE_PATH_DEFAULT,
  2035. ".*", False, False)
  2036. if not os.path.exists(ts_path):
  2037. print 'File not found.'
  2038. ts_password = read_password("", ".*", "Password for TrustStore:", "Invalid characters in password")
  2039. ldap_property_value_map[SSL_TRUSTSTORE_TYPE_PROPERTY] = ts_type
  2040. ldap_property_value_map[SSL_TRUSTSTORE_PATH_PROPERTY] = ts_path
  2041. ldap_property_value_map[SSL_TRUSTSTORE_PASSWORD_PROPERTY] = ts_password
  2042. pass
  2043. else:
  2044. properties.removeOldProp(SSL_TRUSTSTORE_TYPE_PROPERTY)
  2045. properties.removeOldProp(SSL_TRUSTSTORE_PATH_PROPERTY)
  2046. properties.removeOldProp(SSL_TRUSTSTORE_PASSWORD_PROPERTY)
  2047. pass
  2048. print '=' * 20
  2049. print 'Review Settings'
  2050. print '=' * 20
  2051. for property in ldap_property_list_reqd:
  2052. if property in ldap_property_value_map:
  2053. print("%s: %s" % (property, ldap_property_value_map[property]))
  2054. for property in ldap_property_list_opt:
  2055. if ldap_property_value_map.has_key(property):
  2056. if property not in ldap_property_list_passwords:
  2057. print("%s: %s" % (property, ldap_property_value_map[property]))
  2058. else:
  2059. print("%s: %s" % (property, "****"))
  2060. save_settings = get_YN_input("Save settings [y/n] (y)? ", True)
  2061. if save_settings:
  2062. ldap_property_value_map[CLIENT_SECURITY_KEY] = 'ldap'
  2063. # Persisting values
  2064. update_properties(properties, ldap_property_value_map)
  2065. print 'Saving...done'
  2066. return 0
  2067. def read_master_key():
  2068. passwordPattern = ".*"
  2069. passwordDescr = "Invalid characters in password. Use only alphanumeric or "\
  2070. "_ or - characters"
  2071. passwordDefault = ""
  2072. masterKey = get_validated_string_input(
  2073. "Please provide master key for locking the credential store: ",
  2074. passwordDefault, passwordPattern, passwordDescr, True, True)
  2075. if not masterKey:
  2076. print "Master Key cannot be empty!"
  2077. return read_master_key()
  2078. masterKey2 = get_validated_string_input( "Re-enter master key: ",
  2079. passwordDefault, passwordPattern, passwordDescr, True, True)
  2080. if masterKey != masterKey2:
  2081. print "Master key did not match!"
  2082. return read_master_key()
  2083. return masterKey
  2084. def encrypt_password(alias, password):
  2085. properties = get_ambari_properties()
  2086. if properties == -1:
  2087. raise FatalException(1, None)
  2088. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  2089. if isSecure and isSecure.lower() == 'true':
  2090. keyLocation = get_master_key_location(properties)
  2091. masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
  2092. masterKey = None
  2093. if not masterKeyFile:
  2094. # Encryption enabled but no master key file found
  2095. masterKey = get_validated_string_input("Please provide master key " +\
  2096. "for unlocking credential store: ", "", ".*", "", False, False)
  2097. retCode = save_passwd_for_alias(alias, password, masterKey)
  2098. if retCode != 0:
  2099. print 'Failed to save secure password!'
  2100. return password
  2101. else:
  2102. return get_alias_string(alias)
  2103. return password
  2104. def decrypt_password_for_alias(alias):
  2105. properties = get_ambari_properties()
  2106. if properties == -1:
  2107. raise FatalException(1, None)
  2108. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  2109. if isSecure and isSecure.lower() == 'true':
  2110. keyLocation = get_master_key_location(properties)
  2111. masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
  2112. masterKey = None
  2113. if not masterKeyFile:
  2114. # Encryption enabled but no master key file found
  2115. masterKey = get_validated_string_input("Please provide master key " +\
  2116. "for unlocking credential store: ", "", ".*", "", False, False)
  2117. return read_passwd_for_alias(alias, masterKey)
  2118. else:
  2119. return alias
  2120. def setup_master_key():
  2121. if not is_root():
  2122. err = 'Ambari-server setup should be run with '\
  2123. 'root-level privileges'
  2124. raise FatalException(4, err)
  2125. properties = get_ambari_properties()
  2126. if properties == -1:
  2127. raise FatalException(1, "Failed to read properties file.")
  2128. # Check configuration for location of master key
  2129. keyLocation = get_master_key_location(properties)
  2130. masterKeyFile = search_file(SECURITY_MASTER_KEY_FILENAME, keyLocation)
  2131. isPersisted = True if masterKeyFile else False
  2132. isSecure = properties.get_property(SECURITY_IS_ENCRYPTION_ENABLED)
  2133. isSecure = True if isSecure and isSecure.lower() == 'true' else False
  2134. db_password = properties.get_property(JDBC_PASSWORD_PROPERTY)
  2135. # Read clear text password from from
  2136. if db_password and not is_alias_string(db_password) and os.path.isfile(db_password):
  2137. with open(db_password, 'r') as file:
  2138. db_password = file.read()
  2139. ldap_password = properties.get_property(LDAP_MGR_PASSWORD_PROPERTY)
  2140. resetKey = False
  2141. masterKey = None
  2142. if isSecure:
  2143. resetKey = get_YN_input("Password encryption is enabled. Do you want to "
  2144. "reset master key? [y/n] (n): ", False)
  2145. # For encrypting of only unencrypted passwords without resetting the key ask
  2146. # for master key if not persisted.
  2147. if isSecure and not isPersisted and not resetKey:
  2148. masterKey = get_validated_string_input('Please provide master key for '
  2149. 'the credential store: ', "", ".*", "", True, False)
  2150. pass
  2151. # Make sure both passwords are clear-text if master key is lost
  2152. if resetKey:
  2153. if not isPersisted:
  2154. masterKey = get_validated_string_input('Please provide original master '
  2155. 'key for the credential store. Press [Enter] to skip: ',
  2156. "", ".*", "", True, True)
  2157. if not masterKey:
  2158. err = '{0} is already encrypted. Please call {1} to store unencrypted' \
  2159. ' password and call "encrypt-passwords" again.'
  2160. if db_password and is_alias_string(db_password):
  2161. print err.format('Database password', '"' + SETUP_ACTION + '"')
  2162. return 1
  2163. if ldap_password and is_alias_string(ldap_password):
  2164. print err.format('LDAP manager password', '"' + LDAP_SETUP_ACTION + '"')
  2165. return 1
  2166. pass
  2167. pass
  2168. pass
  2169. # Read back any encrypted passwords
  2170. if db_password and is_alias_string(db_password):
  2171. db_password = read_passwd_for_alias(JDBC_RCA_PASSWORD_ALIAS, masterKey)
  2172. if ldap_password and is_alias_string(ldap_password):
  2173. ldap_password = read_passwd_for_alias(LDAP_MGR_PASSWORD_ALIAS, masterKey)
  2174. # Read master key, if non-secure or reset is true
  2175. if resetKey or not isSecure:
  2176. masterKey = read_master_key()
  2177. persist = get_YN_input("Do you want to persist master key. If you choose "\
  2178. "not to persist, you need to provide the master "\
  2179. "key while starting the ambari server as an env "\
  2180. "variable named " + SECURITY_KEY_ENV_VAR_NAME +\
  2181. " or the start will prompt for the master key."
  2182. " Persist [y/n] (y)? ", True)
  2183. if persist:
  2184. save_master_key(masterKey, keyLocation + os.sep +
  2185. SECURITY_MASTER_KEY_FILENAME, persist)
  2186. elif not persist and masterKeyFile:
  2187. try:
  2188. os.remove(masterKeyFile)
  2189. print_info_msg("Deleting master key file at location: " + str(
  2190. masterKeyFile))
  2191. except Exception, e:
  2192. print 'Could not remove master key file. %s' % e
  2193. pass
  2194. pass
  2195. if resetKey and masterKey:
  2196. # Blow up the credential store made with previous key
  2197. store_file = get_credential_store_location(properties)
  2198. if os.path.exists(store_file):
  2199. os.remove(store_file)
  2200. pass
  2201. propertyMap = {SECURITY_IS_ENCRYPTION_ENABLED : 'true'}
  2202. # Encrypt only un-encrypted passwords
  2203. if db_password and not is_alias_string(db_password):
  2204. retCode = save_passwd_for_alias(JDBC_RCA_PASSWORD_ALIAS, db_password, masterKey)
  2205. propertyMap[JDBC_PASSWORD_PROPERTY] = get_alias_string(JDBC_RCA_PASSWORD_ALIAS)
  2206. if retCode != 0:
  2207. print 'Failed to save secure database password.'
  2208. else:
  2209. remove_password_file(JDBC_PASSWORD_FILENAME)
  2210. pass
  2211. if ldap_password and not is_alias_string(ldap_password):
  2212. retCode = save_passwd_for_alias(LDAP_MGR_PASSWORD_ALIAS, ldap_password, masterKey)
  2213. propertyMap[LDAP_MGR_PASSWORD_PROPERTY] = get_alias_string(LDAP_MGR_PASSWORD_ALIAS)
  2214. if retCode != 0:
  2215. print 'Failed to save secure LDAP password.'
  2216. pass
  2217. update_properties(propertyMap)
  2218. # Since files for store and master are created we need to ensure correct
  2219. # permissions
  2220. ambari_user = read_ambari_user()
  2221. if ambari_user:
  2222. adjust_directory_permissions(ambari_user)
  2223. return 0
  2224. def get_credential_store_location(properties):
  2225. store_loc = properties[SECURITY_KEYS_DIR]
  2226. if store_loc is None or store_loc == "":
  2227. store_loc = "/var/lib/ambari-server/keys/credentials.jceks"
  2228. else:
  2229. store_loc += os.sep + "credentials.jceks"
  2230. return store_loc
  2231. def get_master_key_location(properties):
  2232. keyLocation = properties[SECURITY_MASTER_KEY_LOCATION]
  2233. if keyLocation is None or keyLocation == "":
  2234. keyLocation = properties[SECURITY_KEYS_DIR]
  2235. return keyLocation
  2236. def is_alias_string(passwdStr):
  2237. regex = re.compile("\$\{alias=[\w\.]+\}")
  2238. # Match implies string at beginning of word
  2239. r = regex.match(passwdStr)
  2240. if r is not None:
  2241. return True
  2242. else:
  2243. return False
  2244. def get_alias_string(alias):
  2245. return "${alias=" + alias + "}"
  2246. def get_alias_from_alias_string(aliasStr):
  2247. return aliasStr[8:-1]
  2248. def read_passwd_for_alias(alias, masterKey=""):
  2249. if alias:
  2250. jdk_path = find_jdk()
  2251. if jdk_path is None:
  2252. print_error_msg("No JDK found, please run the \"setup\" "
  2253. "command to install a JDK automatically or install any "
  2254. "JDK manually to " + JDK_INSTALL_DIR)
  2255. return 1
  2256. tempFileName = "ambari.passwd"
  2257. passwd = ""
  2258. tempDir = tempfile.gettempdir()
  2259. #create temporary file for writing
  2260. tempFilePath = tempDir + os.sep + tempFileName
  2261. file = open(tempFilePath, 'w+')
  2262. os.chmod(tempFilePath, stat.S_IREAD | stat.S_IWRITE)
  2263. file.close()
  2264. if masterKey is None or masterKey == "":
  2265. masterKey = "None"
  2266. command = SECURITY_PROVIDER_GET_CMD.format(jdk_path,
  2267. get_conf_dir(), get_ambari_classpath(), alias, tempFilePath, masterKey)
  2268. (retcode, stdout, stderr) = run_os_command(command)
  2269. print_info_msg("Return code from credential provider get passwd: " +
  2270. str(retcode))
  2271. if retcode != 0:
  2272. print 'Unable to read password from store. alias = ' + alias
  2273. else:
  2274. passwd = open(tempFilePath, 'r').read()
  2275. # Remove temporary file
  2276. os.remove(tempFilePath)
  2277. return passwd
  2278. else:
  2279. print_error_msg("Alias is unreadable.")
  2280. def save_passwd_for_alias(alias, passwd, masterKey=""):
  2281. if alias and passwd:
  2282. jdk_path = find_jdk()
  2283. if jdk_path is None:
  2284. print_error_msg("No JDK found, please run the \"setup\" "
  2285. "command to install a JDK automatically or install any "
  2286. "JDK manually to " + JDK_INSTALL_DIR)
  2287. return 1
  2288. if masterKey is None or masterKey == "":
  2289. masterKey = "None"
  2290. command = SECURITY_PROVIDER_PUT_CMD.format(jdk_path, get_conf_dir(),
  2291. get_ambari_classpath(), alias, passwd, masterKey)
  2292. (retcode, stdout, stderr) = run_os_command(command)
  2293. print_info_msg("Return code from credential provider save passwd: " +
  2294. str(retcode))
  2295. return retcode
  2296. else:
  2297. print_error_msg("Alias or password is unreadable.")
  2298. def save_master_key(master_key, key_location, persist=True):
  2299. if master_key:
  2300. jdk_path = find_jdk()
  2301. if jdk_path is None:
  2302. print_error_msg("No JDK found, please run the \"setup\" "
  2303. "command to install a JDK automatically or install any "
  2304. "JDK manually to " + JDK_INSTALL_DIR)
  2305. return 1
  2306. command = SECURITY_PROVIDER_KEY_CMD.format(jdk_path,
  2307. get_ambari_classpath(), get_conf_dir(), master_key, key_location, persist)
  2308. (retcode, stdout, stderr) = run_os_command(command)
  2309. print_info_msg("Return code from credential provider save KEY: " +
  2310. str(retcode))
  2311. else:
  2312. print_error_msg("Master key cannot be None.")
  2313. def configure_ldap_password():
  2314. passwordDefault = ""
  2315. passwordPrompt = 'Enter Manager Password* : '
  2316. passwordPattern = ".*"
  2317. passwordDescr = "Invalid characters in password."
  2318. password = read_password(passwordDefault, passwordPattern, passwordPrompt,
  2319. passwordDescr)
  2320. return password
  2321. # Copy file to /tmp and save with file.# (largest # is latest file)
  2322. def backup_file_in_temp(filePath):
  2323. if filePath is not None:
  2324. tmpDir = tempfile.gettempdir()
  2325. back_up_file_count = len(glob.glob1(tmpDir, AMBARI_PROPERTIES_FILE + "*"))
  2326. try:
  2327. shutil.copyfile(filePath, tmpDir + os.sep +
  2328. AMBARI_PROPERTIES_FILE + "." + str(back_up_file_count + 1))
  2329. except (Exception), e:
  2330. print_error_msg('Could not backup file in temp "%s": %s' % (str(
  2331. back_up_file_count, e)))
  2332. return 0
  2333. # update properties in a section-less properties file
  2334. # Cannot use ConfigParser due to bugs in version 2.6
  2335. def update_properties(propertyMap):
  2336. conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
  2337. backup_file_in_temp(conf_file)
  2338. if propertyMap is not None and conf_file is not None:
  2339. properties = Properties()
  2340. try:
  2341. with open(conf_file, 'r') as file:
  2342. properties.load(file)
  2343. except (Exception), e:
  2344. print_error_msg ('Could not read "%s": %s' % (conf_file, e))
  2345. return -1
  2346. #for key in propertyMap.keys():
  2347. #properties[key] = propertyMap[key]
  2348. for key in propertyMap.keys():
  2349. properties.removeOldProp(key)
  2350. properties.process_pair(key, str(propertyMap[key]))
  2351. with open(conf_file, 'w') as file:
  2352. properties.store(file)
  2353. return 0
  2354. def update_properties(properties, propertyMap):
  2355. conf_file = search_file(AMBARI_PROPERTIES_FILE, get_conf_dir())
  2356. backup_file_in_temp(conf_file)
  2357. if conf_file is not None:
  2358. if propertyMap is not None:
  2359. for key in propertyMap.keys():
  2360. properties.removeOldProp(key)
  2361. properties.process_pair(key, str(propertyMap[key]))
  2362. pass
  2363. with open(conf_file, 'w') as file:
  2364. properties.store(file)
  2365. pass
  2366. pass
  2367. def setup_https(args):
  2368. if not is_root():
  2369. err = 'Ambari-server setup-https should be run with ' \
  2370. 'root-level privileges'
  2371. raise FatalException(4, err)
  2372. args.exit_message = None
  2373. if not SILENT:
  2374. properties = get_ambari_properties()
  2375. try:
  2376. security_server_keys_dir = properties.get_property(SSL_KEY_DIR)
  2377. client_api_ssl_port = DEFAULT_SSL_API_PORT if properties.get_property(SSL_API_PORT) in ("")\
  2378. else properties.get_property(SSL_API_PORT)
  2379. api_ssl = properties.get_property(SSL_API) in ['true']
  2380. cert_was_imported = False
  2381. cert_must_import = True
  2382. if api_ssl:
  2383. if get_YN_input("Do you want to disable SSL [y/n] n? ", False):
  2384. properties.process_pair(SSL_API, "false")
  2385. cert_must_import=False
  2386. else:
  2387. properties.process_pair(SSL_API_PORT, \
  2388. get_validated_string_input(\
  2389. "SSL port ["+str(client_api_ssl_port)+"] ? ",\
  2390. str(client_api_ssl_port),\
  2391. "^[0-9]{1,5}$", "Invalid port.", False))
  2392. cert_was_imported = import_cert_and_key_action(security_server_keys_dir, properties)
  2393. else:
  2394. if get_YN_input("Do you want to configure HTTPS (y/n) y? ", True):
  2395. properties.process_pair(SSL_API_PORT,\
  2396. get_validated_string_input("SSL port ["+str(client_api_ssl_port)+"] ? ",\
  2397. str(client_api_ssl_port), "^[0-9]{1,5}$", "Invalid port.", False))
  2398. cert_was_imported = import_cert_and_key_action(security_server_keys_dir, properties)
  2399. else:
  2400. return
  2401. if cert_must_import and not cert_was_imported:
  2402. print 'Setup of HTTPS failed. Exiting.'
  2403. return
  2404. conf_file = find_properties_file()
  2405. f = open(conf_file, 'w')
  2406. properties.store(f, "Changed by 'ambari-server setup-https' command")
  2407. if is_server_runing():
  2408. print 'NOTE: Restart Ambari Server to apply changes'+\
  2409. ' ("ambari-server restart|stop|start")'
  2410. except (KeyError), e:
  2411. err = 'Property ' + str(e) + ' is not defined at ' + conf_file
  2412. raise FatalException(1, err)
  2413. else:
  2414. print "setup-https is not enabled in silent mode."
  2415. ambari_user = read_ambari_user()
  2416. if ambari_user:
  2417. adjust_directory_permissions(ambari_user)
  2418. def is_server_runing():
  2419. if os.path.exists(PID_DIR + os.sep + PID_NAME):
  2420. f = open(PID_DIR + os.sep + PID_NAME, "r")
  2421. pid = int(f.readline())
  2422. f.close()
  2423. retcode, out, err = run_os_command("ps -p " + str(pid))
  2424. if retcode == 0:
  2425. return True, pid
  2426. else:
  2427. return False, None
  2428. else:
  2429. return False, None
  2430. def import_cert_and_key_action(security_server_keys_dir, properties):
  2431. if import_cert_and_key(security_server_keys_dir):
  2432. properties.process_pair(SSL_SERVER_CERT_NAME, SSL_CERT_FILE_NAME)
  2433. properties.process_pair(SSL_SERVER_KEY_NAME, SSL_KEY_FILE_NAME)
  2434. properties.process_pair(SSL_API, "true")
  2435. return True
  2436. else:
  2437. return False
  2438. def import_cert_and_key(security_server_keys_dir):
  2439. import_cert_path = get_validated_filepath_input(\
  2440. "Please enter path to Certificate: ",\
  2441. "Certificate not found")
  2442. import_key_path = get_validated_filepath_input(\
  2443. "Please enter path to Private Key: ", "Private Key not found")
  2444. pem_password = get_validated_string_input("Please enter password for private key: ", "", None, None, True)
  2445. certInfoDict = get_cert_info(import_cert_path)
  2446. if not certInfoDict:
  2447. print_warning_msg('Error getting certificate information')
  2448. else:
  2449. #Validate common name of certificate
  2450. if not is_valid_cert_host(certInfoDict):
  2451. print_warning_msg('Validation of certificate hostname failed')
  2452. #Validate issue and expirations dates of certificate
  2453. if not is_valid_cert_exp(certInfoDict):
  2454. print_warning_msg('Validation of certificate issue and expiration dates failed')
  2455. #jetty requires private key files with non-empty key passwords
  2456. retcode = 0
  2457. err = ''
  2458. if not pem_password:
  2459. print 'Generating random password for HTTPS keystore...done.'
  2460. pem_password = generate_random_string()
  2461. retcode, out, err = run_os_command(CHANGE_KEY_PWD_CND.format(
  2462. import_key_path, pem_password))
  2463. import_key_path += '.secured'
  2464. if retcode == 0:
  2465. keystoreFilePath = os.path.join(security_server_keys_dir,\
  2466. SSL_KEYSTORE_FILE_NAME)
  2467. passFilePath = os.path.join(security_server_keys_dir,\
  2468. SSL_KEY_PASSWORD_FILE_NAME)
  2469. retcode, out, err = run_os_command(EXPRT_KSTR_CMD.format(import_cert_path,\
  2470. import_key_path, pem_password, keystoreFilePath))
  2471. if retcode == 0:
  2472. print 'Importing and saving certificate...done.'
  2473. set_file_permissions(keystoreFilePath, "660", read_ambari_user(), False)
  2474. with open(passFilePath, 'w+') as passFile:
  2475. passFile.write(pem_password)
  2476. pass
  2477. set_file_permissions(passFilePath, "660", read_ambari_user(), False)
  2478. import_file_to_keystore(import_cert_path, os.path.join(\
  2479. security_server_keys_dir, SSL_CERT_FILE_NAME))
  2480. import_file_to_keystore(import_key_path, os.path.join(\
  2481. security_server_keys_dir, SSL_KEY_FILE_NAME))
  2482. return True
  2483. else:
  2484. print_error_msg('Could not import Certificate and Private Key.')
  2485. print 'SSL error on exporting keystore: ' + err.rstrip() + '.'
  2486. return False
  2487. def import_file_to_keystore(source, destination):
  2488. shutil.copy(source, destination)
  2489. set_file_permissions(destination, "660", read_ambari_user(), False)
  2490. def generate_random_string(length=SSL_KEY_PASSWORD_LENGTH):
  2491. chars = string.digits + string.ascii_letters
  2492. return ''.join(random.choice(chars) for x in range(length))
  2493. def get_validated_filepath_input(prompt, description, default=None):
  2494. input = False
  2495. while not input:
  2496. if SILENT:
  2497. print (prompt)
  2498. return default
  2499. else:
  2500. input = raw_input(prompt)
  2501. if not input==None:
  2502. input = input.strip()
  2503. if not input==None and not ""==input and os.path.exists(input):
  2504. return input
  2505. else:
  2506. print description
  2507. input=False
  2508. def get_cert_info(path):
  2509. retcode, out, err = run_os_command(GET_CRT_INFO_CMD.format(path))
  2510. if retcode != 0:
  2511. print 'Error during getting certificate info'
  2512. print err
  2513. return None
  2514. if out:
  2515. certInfolist = out.split(os.linesep)
  2516. else:
  2517. print 'Empty certificate info'
  2518. return None
  2519. notBefore = None
  2520. notAfter = None
  2521. subject = None
  2522. for item in range(len(certInfolist)):
  2523. if certInfolist[item].startswith('notAfter='):
  2524. notAfter = certInfolist[item].split('=')[1]
  2525. if certInfolist[item].startswith('notBefore='):
  2526. notBefore = certInfolist[item].split('=')[1]
  2527. if certInfolist[item].startswith('subject='):
  2528. subject = certInfolist[item].split('=', 1)[1]
  2529. #Convert subj to dict
  2530. pattern = re.compile(r"[A-Z]{1,2}=[\w.-]{1,}")
  2531. if subject:
  2532. subjList = pattern.findall(subject)
  2533. keys = [item.split('=')[0] for item in subjList]
  2534. values = [item.split('=')[1] for item in subjList]
  2535. subjDict = dict(zip(keys, values))
  2536. result = subjDict
  2537. result['notBefore'] = notBefore
  2538. result['notAfter'] = notAfter
  2539. result['subject'] = subject
  2540. return result
  2541. else:
  2542. return {}
  2543. def is_valid_cert_exp(certInfoDict):
  2544. if certInfoDict.has_key(NOT_BEFORE_ATTR):
  2545. notBefore = certInfoDict[NOT_BEFORE_ATTR]
  2546. else:
  2547. print_warning_msg('There is no Not Before value in certificate')
  2548. return False
  2549. if certInfoDict.has_key(NOT_AFTER_ATTR):
  2550. notAfter = certInfoDict['notAfter']
  2551. else:
  2552. print_warning_msg('There is no Not After value in certificate')
  2553. return False
  2554. notBeforeDate = datetime.datetime.strptime(notBefore, SSL_DATE_FORMAT)
  2555. notAfterDate = datetime.datetime.strptime(notAfter, SSL_DATE_FORMAT)
  2556. currentDate = datetime.datetime.now()
  2557. if currentDate > notAfterDate:
  2558. print_warning_msg('Certificate was expired on: ' + str(notAfterDate))
  2559. return False
  2560. if currentDate < notBeforeDate:
  2561. print_warning_msg('Certificate will be active from: ' + str(notBeforeDate))
  2562. return False
  2563. return True
  2564. def is_valid_cert_host(certInfoDict):
  2565. if certInfoDict.has_key(COMMON_NAME_ATTR):
  2566. commonName = certInfoDict[COMMON_NAME_ATTR]
  2567. else:
  2568. print_warning_msg('There is no Common name in certificate')
  2569. return False
  2570. fqdn = get_fqdn()
  2571. if not fqdn:
  2572. print_warning_msg('Failed to get server FQDN')
  2573. return False
  2574. if commonName != fqdn:
  2575. print_warning_msg('Common name in certificate: ' + commonName + ' doesn\'t matches the server hostname: ' + fqdn)
  2576. return False
  2577. return True
  2578. def get_fqdn():
  2579. properties = get_ambari_properties()
  2580. if properties == -1:
  2581. print "Error getting ambari properties"
  2582. return None
  2583. get_fqdn_service_url = properties[GET_FQDN_SERVICE_URL]
  2584. try:
  2585. handle = urllib2.urlopen(get_fqdn_service_url, '', 2)
  2586. str = handle.read()
  2587. handle.close()
  2588. return str
  2589. except Exception, e:
  2590. return socket.getfqdn()
  2591. #
  2592. # Main.
  2593. #
  2594. def main():
  2595. parser = optparse.OptionParser(usage="usage: %prog [options] action [stack_id]",)
  2596. parser.add_option('-f', '--init-script-file',
  2597. default='/var/lib/ambari-server/'
  2598. 'resources/Ambari-DDL-Postgres-CREATE.sql',
  2599. help="File with setup script")
  2600. parser.add_option('-r', '--drop-script-file', default="/var/lib/"
  2601. "ambari-server/resources/"
  2602. "Ambari-DDL-Postgres-DROP.sql",
  2603. help="File with drop script")
  2604. parser.add_option('-u', '--upgrade-script-file', default="/var/lib/"
  2605. "ambari-server/resources/upgrade/ddl/"
  2606. "Ambari-DDL-Postgres-UPGRADE-1.3.0.sql",
  2607. help="File with upgrade script")
  2608. parser.add_option('-t', '--upgrade-stack-script-file', default="/var/lib/"
  2609. "ambari-server/resources/upgrade/dml/"
  2610. "Ambari-DML-Postgres-UPGRADE_STACK.sql",
  2611. help="File with stack upgrade script")
  2612. parser.add_option('-j', '--java-home', default=None,
  2613. help="Use specified java_home. Must be valid on all hosts")
  2614. parser.add_option('-i', '--jdk-location', dest="jdk_location", default=None,
  2615. help="Use specified JDK file in local filesystem instead of downloading")
  2616. parser.add_option('-c', '--jce-policy', default=None,
  2617. help="Use specified jce_policy. Must be valid on all hosts", dest="jce_policy")
  2618. parser.add_option("-v", "--verbose",
  2619. action="store_true", dest="verbose", default=False,
  2620. help="Print verbose status messages")
  2621. parser.add_option("-s", "--silent",
  2622. action="store_true", dest="silent", default=False,
  2623. help="Silently accepts default prompt values")
  2624. parser.add_option('-g', '--debug', action="store_true", dest='debug', default=False,
  2625. help="Start ambari-server in debug mode")
  2626. parser.add_option('--database', default=None, help ="Database to use postgres|oracle", dest="database")
  2627. parser.add_option('--databasehost', default=None, help="Hostname of database server", dest="database_host")
  2628. parser.add_option('--databaseport', default=None, help="Database port", dest="database_port")
  2629. parser.add_option('--databasename', default=None, help="Database/Schema/Service name or ServiceID",
  2630. dest="database_name")
  2631. parser.add_option('--databaseusername', default=None, help="Database user login", dest="database_username")
  2632. parser.add_option('--databasepassword', default=None, help="Database user password", dest="database_password")
  2633. parser.add_option('--sidorsname', default="sname", help="Oracle database identifier type, Service ID/Service "
  2634. "Name sid|sname", dest="sid_or_sname")
  2635. (options, args) = parser.parse_args()
  2636. # set verbose
  2637. global VERBOSE
  2638. VERBOSE = options.verbose
  2639. # set silent
  2640. global SILENT
  2641. SILENT = options.silent
  2642. # debug mode
  2643. global SERVER_DEBUG_MODE
  2644. SERVER_DEBUG_MODE = options.debug
  2645. global DATABASE_INDEX
  2646. global PROMPT_DATABASE_OPTIONS
  2647. #perform checks
  2648. options.warnings = []
  2649. if options.database is None \
  2650. and options.database_host is None \
  2651. and options.database_port is None \
  2652. and options.database_name is None \
  2653. and options.database_username is None \
  2654. and options.database_password is None:
  2655. PROMPT_DATABASE_OPTIONS = True
  2656. elif not (options.database is not None
  2657. and options.database_host is not None
  2658. and options.database_port is not None
  2659. and options.database_name is not None
  2660. and options.database_username is not None
  2661. and options.database_password is not None):
  2662. parser.error('All database options should be set. Please see help for the options.')
  2663. #correct database
  2664. if options.database is not None and options.database not in DATABASE_NAMES:
  2665. parser.print_help()
  2666. parser.error("Unsupported Database " + options.database)
  2667. elif options.database is not None:
  2668. options.database = options.database.lower()
  2669. DATABASE_INDEX = DATABASE_NAMES.index(options.database)
  2670. #correct port
  2671. if options.database_port is not None:
  2672. correct=False
  2673. try:
  2674. port = int(options.database_port)
  2675. if 65536 > port > 0:
  2676. correct = True
  2677. except ValueError:
  2678. pass
  2679. if not correct:
  2680. parser.print_help()
  2681. parser.error("Incorrect database port " + options.database_port)
  2682. if options.database is not None and options.database == "postgres":
  2683. print "WARNING: HostName for postgres server " + options.database_host + \
  2684. " will be ignored: using localhost."
  2685. options.database_host = "localhost"
  2686. if options.sid_or_sname.lower() not in ["sid", "sname"]:
  2687. print "WARNING: Valid values for sid_or_sname are 'sid' or 'sname'. Use 'sid' if the db identifier type is " \
  2688. "Service ID. Use 'sname' if the db identifier type is Service Name"
  2689. parser.print_help()
  2690. exit(-1)
  2691. else:
  2692. options.sid_or_sname = options.sid_or_sname.lower()
  2693. if len(args) == 0:
  2694. print parser.print_help()
  2695. parser.error("No action entered")
  2696. action = args[0]
  2697. if action == UPGRADE_STACK_ACTION:
  2698. args_number_required = 2
  2699. else:
  2700. args_number_required = 1
  2701. if len(args) < args_number_required:
  2702. print parser.print_help()
  2703. parser.error("Invalid number of arguments. Entered: " + str(len(args)) + ", required: " + str(args_number_required))
  2704. options.exit_message = "Ambari Server '%s' completed successfully." % action
  2705. try:
  2706. if action == SETUP_ACTION:
  2707. setup(options)
  2708. elif action == START_ACTION:
  2709. start(options)
  2710. elif action == STOP_ACTION:
  2711. stop(options)
  2712. elif action == RESET_ACTION:
  2713. reset(options)
  2714. elif action == STATUS_ACTION:
  2715. status(options)
  2716. elif action == UPGRADE_ACTION:
  2717. upgrade(options)
  2718. elif action == UPGRADE_STACK_ACTION:
  2719. stack_id = args[1]
  2720. upgrade_stack(options, stack_id)
  2721. elif action == LDAP_SETUP_ACTION:
  2722. setup_ldap()
  2723. elif action == ENCRYPT_PASSWORDS_ACTION:
  2724. setup_master_key()
  2725. elif action == UPDATE_METAINFO_ACTION:
  2726. update_metainfo(options)
  2727. elif action == SETUP_HTTPS_ACTION:
  2728. setup_https(options)
  2729. else:
  2730. parser.error("Invalid action")
  2731. except FatalException as e:
  2732. if e.reason is not None:
  2733. print_error_msg("Exiting with exit code {0}. Reason: {1}".format(e.code, e.reason))
  2734. sys.exit(e.code)
  2735. except NonFatalException as e:
  2736. options.exit_message = "Ambari Server '%s' completed with warnings." % action
  2737. if e.reason is not None:
  2738. print_warning_msg(e.reason)
  2739. if options.exit_message is not None:
  2740. print options.exit_message
  2741. # A Python replacement for java.util.Properties
  2742. # Based on http://code.activestate.com/recipes
  2743. # /496795-a-python-replacement-for-javautilproperties/
  2744. class Properties(object):
  2745. def __init__(self, props=None):
  2746. self._props = {}
  2747. self._origprops = {}
  2748. self._keymap = {}
  2749. self.othercharre = re.compile(r'(?<!\\)(\s*\=)|(?<!\\)(\s*\:)')
  2750. self.othercharre2 = re.compile(r'(\s*\=)|(\s*\:)')
  2751. self.bspacere = re.compile(r'\\(?!\s$)')
  2752. def __parse(self, lines):
  2753. lineno = 0
  2754. i = iter(lines)
  2755. for line in i:
  2756. lineno += 1
  2757. line = line.strip()
  2758. if not line: continue
  2759. if line[0] == '#': continue
  2760. escaped = False
  2761. sepidx = -1
  2762. flag = 0
  2763. m = self.othercharre.search(line)
  2764. if m:
  2765. first, last = m.span()
  2766. start, end = 0, first
  2767. flag = 1
  2768. wspacere = re.compile(r'(?<![\\\=\:])(\s)')
  2769. else:
  2770. if self.othercharre2.search(line):
  2771. wspacere = re.compile(r'(?<![\\])(\s)')
  2772. start, end = 0, len(line)
  2773. m2 = wspacere.search(line, start, end)
  2774. if m2:
  2775. first, last = m2.span()
  2776. sepidx = first
  2777. elif m:
  2778. first, last = m.span()
  2779. sepidx = last - 1
  2780. while line[-1] == '\\':
  2781. nextline = i.next()
  2782. nextline = nextline.strip()
  2783. lineno += 1
  2784. line = line[:-1] + nextline
  2785. if sepidx != -1:
  2786. key, value = line[:sepidx], line[sepidx + 1:]
  2787. else:
  2788. key, value = line, ''
  2789. self.process_pair(key, value)
  2790. def process_pair(self, key, value):
  2791. oldkey = key
  2792. oldvalue = value
  2793. keyparts = self.bspacere.split(key)
  2794. strippable = False
  2795. lastpart = keyparts[-1]
  2796. if lastpart.find('\\ ') != -1:
  2797. keyparts[-1] = lastpart.replace('\\', '')
  2798. elif lastpart and lastpart[-1] == ' ':
  2799. strippable = True
  2800. key = ''.join(keyparts)
  2801. if strippable:
  2802. key = key.strip()
  2803. oldkey = oldkey.strip()
  2804. oldvalue = self.unescape(oldvalue)
  2805. value = self.unescape(value)
  2806. self._props[key] = None if value is None else value.strip()
  2807. if self._keymap.has_key(key):
  2808. oldkey = self._keymap.get(key)
  2809. self._origprops[oldkey] = None if oldvalue is None else oldvalue.strip()
  2810. else:
  2811. self._origprops[oldkey] = None if oldvalue is None else oldvalue.strip()
  2812. self._keymap[key] = oldkey
  2813. def unescape(self, value):
  2814. newvalue = value
  2815. if not value is None:
  2816. newvalue = value.replace('\:', ':')
  2817. newvalue = newvalue.replace('\=', '=')
  2818. return newvalue
  2819. def removeOldProp(self, key):
  2820. if self._origprops.has_key(key):
  2821. del self._origprops[key]
  2822. pass
  2823. def load(self, stream):
  2824. if type(stream) is not file:
  2825. raise TypeError, 'Argument should be a file object!'
  2826. if stream.mode != 'r':
  2827. raise ValueError, 'Stream should be opened in read-only mode!'
  2828. try:
  2829. self.fileName = os.path.abspath(stream.name)
  2830. lines = stream.readlines()
  2831. self.__parse(lines)
  2832. except IOError, e:
  2833. raise
  2834. def get_property(self, key):
  2835. return self._props.get(key, '')
  2836. def propertyNames(self):
  2837. return self._props.keys()
  2838. def getPropertyDict(self):
  2839. return self._props
  2840. def __getitem__(self, name):
  2841. return self.get_property(name)
  2842. def __getattr__(self, name):
  2843. try:
  2844. return self.__dict__[name]
  2845. except KeyError:
  2846. if hasattr(self._props, name):
  2847. return getattr(self._props, name)
  2848. def store(self, out, header=""):
  2849. """ Write the properties list to the stream 'out' along
  2850. with the optional 'header' """
  2851. if out.mode[0] != 'w':
  2852. raise ValueError,'Steam should be opened in write mode!'
  2853. try:
  2854. out.write(''.join(('#', ASF_LICENSE_HEADER, '\n')))
  2855. out.write(''.join(('#',header,'\n')))
  2856. # Write timestamp
  2857. tstamp = time.strftime('%a %b %d %H:%M:%S %Z %Y', time.localtime())
  2858. out.write(''.join(('#',tstamp,'\n')))
  2859. # Write properties from the pristine dictionary
  2860. for prop, val in self._origprops.items():
  2861. if val is not None:
  2862. out.write(''.join((prop,'=',val,'\n')))
  2863. out.close()
  2864. except IOError, e:
  2865. raise
  2866. if __name__ == "__main__":
  2867. try:
  2868. main()
  2869. except (KeyboardInterrupt, EOFError):
  2870. print("\nAborting ... Keyboard Interrupt.")
  2871. sys.exit(1)