Browse Source
* [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui]Alert plugin design (#3734) * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui] Add alarm instance page * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3189][alert,spi,dao,plugin-api] base code of dolphinscheduler spi and alert plugin implement (#3601) * DS SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * add TODO * delete * compile * spi commit * Plugin Alert * fix some bug * add todo * change web ui from alpacajs to form-create * remove module * add plugin schema * add license header * update alert and spi module version * update the alert plugin sub module version * comment the maven.local.repository param * move utils from spi to common module * add license header * add license header and delete some chinese comment * update spi packages * delete no use alert_xx.properties * update mysql.connector.version back to 5.1.34 * delete no use comment in pom.xml * update email stmp password * add license * add semicolon to sql/upgrade/1.4.0_schema/mysql/dolphinscheduler_ddl.sql file * format the code style * format new clase file with checkstyle * update plugin params to Builder model * move JSONUtils to SPI because plugin can not dependency common module * move JSONUtils to SPI because plugin can not dependency common module * delete collection dependency * replace PluginParamsTransfer to spi PluginParamsTransfer * update dolphinscheduler-maven-plugin to 1.0.0 * update license * update apache-rat-plugin add exclude '.iml' file * check license * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * default datasource should be postgresql * add license files * add license files * postgresql port should be 5432 * postgresql test * mv show_type to spi add license header to AlertConstants * check style fix * copy check style file from branch dev * alert show_type set by plugin * alert show_type set by plugin * add PluginDefineMapper to dolphinscheduler-server/src/test/java/org/apache/dolphinscheduler/server/registry/DependencyConfig.java * add Bean to TaskCallbackServiceTestConfig * add Bean to TaskCallbackServiceTestConfig * fix check style * check style fix * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * fix check style * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * check style fix * rollback test change * rollback test change * rollback dao pom change * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * add ut to pom.xml * add upgrade schema to global schema * fix ut failed * fix ut failed * fix ut failed * fix ut failed * add test EmailAlertPluginTest to pom.xml * fix ut failed * fix ut failed * fix check style * update license header to presto license header * presto license header not check * fix ut coverage * fix ut coverage * fix ut * fix ut * fix ut * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage Co-authored-by: break60 <790061044@qq.com> * Replace the tenant management page ui with element-ui (#3891) * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui] Add alarm instance page * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui]Alert plugin design (#3734) * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui] Add alarm instance page * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3189][alert,spi,dao,plugin-api] base code of dolphinscheduler spi and alert plugin implement (#3601) * DS SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * add TODO * delete * compile * spi commit * Plugin Alert * fix some bug * add todo * change web ui from alpacajs to form-create * remove module * add plugin schema * add license header * update alert and spi module version * update the alert plugin sub module version * comment the maven.local.repository param * move utils from spi to common module * add license header * add license header and delete some chinese comment * update spi packages * delete no use alert_xx.properties * update mysql.connector.version back to 5.1.34 * delete no use comment in pom.xml * update email stmp password * add license * add semicolon to sql/upgrade/1.4.0_schema/mysql/dolphinscheduler_ddl.sql file * format the code style * format new clase file with checkstyle * update plugin params to Builder model * move JSONUtils to SPI because plugin can not dependency common module * move JSONUtils to SPI because plugin can not dependency common module * delete collection dependency * replace PluginParamsTransfer to spi PluginParamsTransfer * update dolphinscheduler-maven-plugin to 1.0.0 * update license * update apache-rat-plugin add exclude '.iml' file * check license * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * default datasource should be postgresql * add license files * add license files * postgresql port should be 5432 * postgresql test * mv show_type to spi add license header to AlertConstants * check style fix * copy check style file from branch dev * alert show_type set by plugin * alert show_type set by plugin * add PluginDefineMapper to dolphinscheduler-server/src/test/java/org/apache/dolphinscheduler/server/registry/DependencyConfig.java * add Bean to TaskCallbackServiceTestConfig * add Bean to TaskCallbackServiceTestConfig * fix check style * check style fix * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * fix check style * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * check style fix * rollback test change * rollback test change * rollback dao pom change * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * add ut to pom.xml * add upgrade schema to global schema * fix ut failed * fix ut failed * fix ut failed * fix ut failed * add test EmailAlertPluginTest to pom.xml * fix ut failed * fix ut failed * fix check style * update license header to presto license header * presto license header not check * fix ut coverage * fix ut coverage * fix ut * fix ut * fix ut * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage Co-authored-by: break60 <790061044@qq.com> * The tenant management module ui is replaced with element-ui * fix * fix * fix * fix * fix * modify * fix Co-authored-by: gaojun2048 <32193458+gaojun2048@users.noreply.github.com> * the alert module support service. * the alert module support service. * Delete blank lines. * add code checkstyle. * Solve the sonar bug. * Re-execute build. * add test. * update ut. * add test class. * update test. * [feature#3356] alert-spi support DingTalk&WeChat (#3869) * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui]Alert plugin design (#3734) * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [feature][ui] Add alarm instance page * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * [Feature-3189][alert,spi,dao,plugin-api] base code of dolphinscheduler spi and alert plugin implement (#3601) * DS SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * Add DolphinScheduler SPI , and rebuilt the code of the Alert plug-in based on SPI * add TODO * delete * compile * spi commit * Plugin Alert * fix some bug * add todo * change web ui from alpacajs to form-create * remove module * add plugin schema * add license header * update alert and spi module version * update the alert plugin sub module version * comment the maven.local.repository param * move utils from spi to common module * add license header * add license header and delete some chinese comment * update spi packages * delete no use alert_xx.properties * update mysql.connector.version back to 5.1.34 * delete no use comment in pom.xml * update email stmp password * add license * add semicolon to sql/upgrade/1.4.0_schema/mysql/dolphinscheduler_ddl.sql file * format the code style * format new clase file with checkstyle * update plugin params to Builder model * move JSONUtils to SPI because plugin can not dependency common module * move JSONUtils to SPI because plugin can not dependency common module * delete collection dependency * replace PluginParamsTransfer to spi PluginParamsTransfer * update dolphinscheduler-maven-plugin to 1.0.0 * update license * update apache-rat-plugin add exclude '.iml' file * check license * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * ArtifactResolver only use in development and configPlugins is not empty * default datasource should be postgresql * add license files * add license files * postgresql port should be 5432 * postgresql test * mv show_type to spi add license header to AlertConstants * check style fix * copy check style file from branch dev * alert show_type set by plugin * alert show_type set by plugin * add PluginDefineMapper to dolphinscheduler-server/src/test/java/org/apache/dolphinscheduler/server/registry/DependencyConfig.java * add Bean to TaskCallbackServiceTestConfig * add Bean to TaskCallbackServiceTestConfig * fix check style * check style fix * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * fix check style * [Feature-3682][ui]Add form-create plug-in and alarm group management add sample demo (#3683) * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * check style fix * rollback test change * rollback test change * rollback dao pom change * [feature-3665][ui]Add element-ui (#3666) * [feature-3665][ui]Add element-ui * add license * Add form-create plug-in and alarm group management add sample demo * Modify node version * fix * fix * add ut to pom.xml * add upgrade schema to global schema * fix ut failed * fix ut failed * fix ut failed * fix ut failed * add test EmailAlertPluginTest to pom.xml * fix ut failed * fix ut failed * fix check style * update license header to presto license header * presto license header not check * fix ut coverage * fix ut coverage * fix ut * fix ut * fix ut * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage * fix ut coverage Co-authored-by: break60 <790061044@qq.com> * [feature#3356] alert-spi support DingTalk this closes # 3356 * add test * code style * we chat alert * support we chat alert * support we chat alert * support we chat alert,update ding talk alert * code style * add test * code style * clean old code * clean old code * code smell * code style * add test * simple config * code style * code style * code style * delete old file * fix log content error Co-authored-by: break60 <790061044@qq.com> Co-authored-by: gaojun2048 <32193458+gaojun2048@users.noreply.github.com> * [FEATURE#4029] alert spi support script alert this closes #4029 * code style * code smell * add test * code style * code smell * code style * fix name error * init sms plugin * modify http type * delete dolphinscheduler-alert-sms plugin * dolphinscheduler plugin need add <package>dolphinscheduler-plugin</package> in the pom.xml file * delete alert http plugin (#4152) delete alert http plugin (#4152) This part of the code was merged by mistake, so I need to delete it * [Feature-3749][Alert-SPI] SqlTask should send notifications by alert server api (#4080) * add sqltask send sync alert server. * update alert-sms license. * update AlertServer test. * remote EmailAlertPluginTest. * update sqltask. * update test class. * [Alert plugin design] add http alert plugin (#4165) * add http alert plugin * [Feature-3311] Add alert plugin instance function (#4038) * [Feature-#3252][build]plugins need put in plugins dir when install (#4259) Update maven build, put the alert plugins in the ${install_dir}/lib/plugin/alert/${plugin_module_name} directory (assembly build and rpm build). Note: When adding a new plug-in, it must be reflected in provisio/dolphinscheduler.xml. this closes #3252 * [Feature#4310][Alert-SPI] Plug-ins containing UI components provide display pages (#4311) * [Feature#4310][Alert-SPI] Plug-ins containing UI components provide display pages *Some plugins (such as alert plugin) need to provide UI interfaces to users. *We use from-creat to dynamically generate UI interfaces. Related parameters are mainly provided by pluginParams. *From-create can generate dynamic ui based on this parameter. this closes #4310 * add license head * rename * add ut * add license * add query plugin detail interface * fix error * [Feature-#3828][server] Delete recipients and CCs in the process defi… (#4303) * [Feature-#3828][server] Delete recipients and CCs in the process definition and select the associated alert group instead * The specific alarm instance associated with the alert group * The process definition only associates the alert group, and does not care about the specific alarm instance. this closes #3828 * remove test cc * remove test cc * fix test error * add sql upgrade script delete alert column(show_type、alert_type、re、cc) * code style * update test Note the statement to delete the column, and provide related instructions * delete AlertGroup field(alert_type) * fix ut error * fix ut error * fix ut error * code style * delete api-doc receiverCC * delete UserAlertGroupMapper * delete UserAlertGroup * delete UserAlertGroupApi * alert group add coulmn user_id * alter user_id to create_user_id * userinfo remove alert group info * Replace the front-end code of the plugin branch with the front-end code of the dev branch (#4353) * Replace the front-end code of the plugin branch with the front-end code of the dev branch * Merge dev to alert_plugin_design (#4351) * fixed queryProcessInstanceListPaging query slow (#3893) because queryProcessInstanceListPaging has contain longtext type field by instance.*,so queryProcessInstanceListPaging query slow , but longtext field not used. * fixed queryTaskInstanceListPaging query slow (#3892) because queryTaskInstanceListPaging has contain longtext type field by instance.*,so queryTaskInstanceListPaging query slow , but longtext field not used. * add verify tenant name cannot contain special characters. (#3865) * [Fix][Docker] fix startup.sh variables cannot reference in single quotes. (#3895) * [Fix][Docker] fix startup.sh variables cannot reference in single quotes.(#3894) Signed-off-by: YoungMan <bushengquan@gmail.com> * Update Dockerfile update the comment and delete the maridb client Co-authored-by: dailidong <dailidong66@gmail.com> * [ambari-plugin]change version 1.3.2 to 1.3.3 (#3935) * [CodeClean][DAO]Remove redundant comments (#3939) * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * dag add close button * reset last version * reset last version * dag add close buttion dag add close buttion * update CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * Update CreateWorkflowLocator.java modify submit workflow button * Update CreateWorkflowLocator.java * Update CreateWorkflowLocator.java modify CLICK_ADD_BUTTON * Update CreateWorkflowLocator.java delete print * Update CreateWorkflowLocator.java 1 * Update CreateWorkflowLocator.java 1 * Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dag.vue * Update dag.vue * Update dag.vue * Update CreateWorkflowLocator.java * Revert "Setting '-XX:+DisableExplicitGC ' causes netty memory leaks" This reverts commitpull/3/MERGE3a2cba7a
* Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dolphinscheduler-daemon.sh * Remove redundant comments ProcessInstanceMapper# queryProcessInstanceListPaging * Remove redundant comments ProcessInstanceMapper# queryProcessInstanceListPaging Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> * fix bug:3615 After the task is executed successfully, but the next task has not been submitted, stop the master * When running a task, the resource file is lost, which results in an error * When running a task, the resource file is lost, which results in an error * When running a task, the resource file is lost, which results in an error * [Fix][api] Add queryProjectCreatedAndAuthorizedByUser function (#3658) * fix getLoginUserCreated bug * fix getLoginUserCreated bug 1 * fix checkstyle * modify function name * modify comment * fix unit test error * rollback sqoop task hive target file Co-authored-by: sunchaohe <sunzhaohe@linklogis.com> Co-authored-by: dailidong <dailidong66@gmail.com> * When running a task, the resource file is lost, which results in an error * When running a task, the resource file is lost, which results in an error * [fixBug-3964][ui]Switch back and forth over timeout alarm, the selected value is empty * solve too many files, close logClientService (#3971) * fix #3966 sub process doesnot send alert mail after process instance ending. (#3972) Co-authored-by: baoliang <baoliang@analysys.com.cn> * [Fix-#3618][server] resolve task executed finished but not release the file handle (#3975) * [Fix-#3618][server] resolve task executed finished but not release the file handle * [Fix-#3618][server] resolve task executed finished but not release the file handle * [Fix-#3958][api] files should not be created successfully in the directory of the authorized file * [FIX-3966] The timeout warning does not take effect in sub_process (#3982) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent Co-authored-by: baoliang <baoliang@analysys.com.cn> * [fix-#3962][api] Avoid ClassCastException for LoggerService.queryLog(). (#3963) * Enhance user experience, add close button to file details page * [Test-3557][API] full cover DataAnalysisServiceImpl (#3605) * generate equals and hashCode method * make up for the state of oblivion * simplify countQueueState method * delete try catch, because this never throw exception * full cover DataAnalysisServiceImpl * improve test coverage * adjust code style * simplify countCommandState method * reduce duplication * simplify countTaskDtos method * Update DataAnalysisServiceImpl.java Co-authored-by: dailidong <dailidong66@gmail.com> * fix import dolphinscheduler_mysql.sql insert admin user data * [FIX-3929] condition task would post wrong tasks when failover. (#3999) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent * remove stdout in logback configuration * fix bug #3929 condition task would post error when failover. * remove unused test * add comments * add skip node judge Co-authored-by: baoliang <baoliang@analysys.com.cn> * [FIX-3929] because of no lock, start up failover would dispatch two same tasks. (#4004) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent * remove stdout in logback configuration * fix bug #3929 condition task would post error when failover. * remove unused test * add comments * add skip node judge * fix bug 3929: because of no lock, start up failover would dispatch two same tasks. Co-authored-by: baoliang <baoliang@analysys.com.cn> * revert pom version to 1.3.3-release * [maven-release-plugin] prepare release 1.3.3 * [maven-release-plugin] prepare for next development iteration * the resources API document does not match the interface parameters * [release]revert pom version to 1.3.3-release * fix bug 4010: remove failed condition tasks from error-task-list. (#4011) Co-authored-by: baoliang <baoliang@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.3 * [maven-release-plugin] prepare for next development iteration * fix bug * reset code * Update udfs.vue * [Feature-3941][ui] Remove tenant name (#3949) * FeatureUI-3941: Removed Tenant * FeatureUI-3941: Removed tenantName in the suggested pages * FeatureUI-3941: Updated the suggested files * FeatureUI-3941: Updated the TenantController * FeatureUI-3941: Updated the TenantController and the pom.xml * FeatureUI-3941: Updated the TenantControllerTest * [Improvement][script] daemon script usage (#3968) * Improvement daemon script usage * don't remove status command don't remove status command Co-authored-by: dailidong <dailidong66@gmail.com> * fix #3688, Optimization of table building statements (#3689) * merge from 1.3.3-release * merge from 1.3.3-release * [Improvement-4012][common/remote] Json util code integration,remove the remote module json util (#4013) * Json util code integration,remove the remote module json util. * update code checkstyle. * update code checkstyle. * add code checkstyle. * add test class. * update JSONUtils class. * update JSONUtils class. * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor code style * refactor code style * refactor code style * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor ut test * refactor ut test * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * fix #3900 kill multi yarn app in one job * refactor ut * merge from 1.3.3-release * refactor ut * refactor ut * refactor * refactor * refactor code style * refactor code style * refactor code style * refactor code style * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * add ProcessUtils UT * refactor code style * refactor code style * refactor code style * refactor code style * [Draft][Merge][133-dev]133 merge dev (#4031) * [Feture-3327][ui]Add the function of re-uploading files in the resource center * [Feture-3327][ui]Add the function of re-uploading files in the resource center (#3394) * Before creating a workflow, clear the canvas * [Fix-3256][ui] herry pick commit from dev for Fix admin user info update error (#3306) * [Feture-3327][ui]Add the function of re-uploading files in the resource center Co-authored-by: wuchunfu <319355703@qq.com> * [Improvement-3327][api]support re-upload the resource file (#3395) * [Fix-3390][server]Running hive sql task need find the hdfs path correctly (#3396) * [Fix-3390][api]Running hive sql task need find the hdfs path correctly * [Fix-3390][api]Running hive sql task need find the hdfs path correctly * update soft version * hive UDF function to modify the background color * fix * fix bug: Fix master task dependency check bug * cancel spark task version check (#3406) Co-authored-by: Eights-Li <yelli.hl@gmail.com> * [Bug][ui]Fix front-end bug #3413 * [Feature][ambari_plugin]support one worker can belongs different worker groups when execute install script (#3410) * Optimize dag * Update actions.js (#3401) * [Fix-3256][ui] Fix admin user info update error (#3425) (#3428) * [PROPOSAL-3139] Datasource selection changes from radio to select * [PROPOSAL-3139] Datasource selection changes from radio to select * [BUG FIX] issues #3256 * [BUG FIX] issues #3256 * [BUG FIX] issues #3256 * [Fix-3256][ui] Fix admin user info update error * [Fix-3256][ui] Fix admin user info update error * [Fix-3256][ui] Fix admin user info update error * [Fix-3256][ui] Fix admin user info update error * reset createUser.vue * [Fix-3256][ui] Fix admin user info update error Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: wuchunfu <319355703@qq.com> Co-authored-by: dailidong <dailidong66@gmail.com> * [Fix-3433][api]Fixed that release the imported process definition which version is below 1.3.0 will be failure * dag connection add check * fix * [Fix-3423][dao][sql]Fixed that the resource file of the task node can't be found when upgrade from 1.2.0 to 1.3.x (#3454) * Remove node deep monitoring * If worker group id is null,don't need to set the value of the worker group (#3460) * [Fix-3423][dao][sql]Fixed that the resource file of the task node can't be found when upgrade from 1.2.0 to 1.3.x * [Fix-3423][dao]If worker group id is null,don't need to set the value of the worker group * [ui]Code optimization * fix * fix * [fix-3058][ui]Move rtTargetArr to jsPlumbHandle.js * [optimization][ui]Prevent the shell script input box from being empty * [Fix-3462][api]If login user is admin,need list all udfs (#3465) * [Fix-3462][api]If login user is admin,need list all udfs * [Fix-3462][api]add the test on the method of QueryUdfFuncList * [Fix-3462][api]fix the code smell * [Fix-3462][api]fix the code smell * [Fix-3462][api]fix the code smell * [Fix-3463][api]Fixed that run the sql task will be failure after rename the udf resource (#3482) * [fixBug-3058][ui]Fix connection abnormalities in historical workflow instance data * [Feture-3327][ui]Add the function of re-uploading files in the udf subdirectory * fix bug: Fix master task dependency check bug (#3473) Co-authored-by: lenboo <baoliang@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.2 * [maven-release-plugin] prepare for next development iteration * fix ci_e2e fail (#3497) * [Fix-3469][api]Should filter the resource by the different program type (#3498) * [Fix-3463][api]Fixed that run the sql task will be failure after rename the udf resource * [Fix-3469][api]Should list python file and jar file * [Fix-3469][api]Should filter the resource by the different program type * [Fix-3469][api]fix the code smell * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test release 1.3.2 version rollback (#3499) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.2 * [maven-release-plugin] prepare for next development iteration * [Fix-3469][ui]The value of maintenance resources and the filtering of resources according to different program types * fix * Revert "fix ci_e2e fail (#3497)" This reverts commite367f90bb7
. * test * test release 1.3.2 version rollback * test release 1.3.2 version rollback (#3503) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test * test release 1.3.2 version rollback Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.2 * [maven-release-plugin] prepare for next development iteration * test release 1.3.2 version rollback (#3504) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test * test release 1.3.2 version rollback Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.2 * [maven-release-plugin] prepare for next development iteration * fix ds muti-level directory in zk, which lead to fail to assign work * add login user check some actions in api * [Hotfix][ci] Fix e2e ci docker image build error * modify tag 1.3.0 to HEAD * modify tag 1.3.0 to HEAD (#3525) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test * test release 1.3.2 version rollback * modify tag 1.3.0 to HEAD Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * remove OGNL part of the mybaits notice (#3526) * [maven-release-plugin] prepare release 1.3.2 * [maven-release-plugin] prepare for next development iteration * release 1.3.2 version rollback (#3527) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test * test release 1.3.2 version rollback * modify tag 1.3.0 to HEAD Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * [ui]Script input box to modify the delay loading time * fix * fix * fix * fix * modify general user can't create token * [ui]It is forbidden to select non-existent resources and modify the tree display data format * modify general user can't create token (#3533) * [Feature] JVM parameter optimization , related issue #3370 * [Feature] JVM parameter optimization , related issue #3370 * test release 1.3.2 version rollback * test release 1.3.2 version rollback * test * test release 1.3.2 version rollback * modify tag 1.3.0 to HEAD * modify general user can't create token Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * if task is null , set task type is null instead of "null" * [Fix-3536][api]If user didn't have tenant,create resource directory will NPE (#3537) * [Fix-3536][api]If user didn't have tenant,create resource will NPE * [Fix-3536][api]If user didn't have tenant,create resource directory will NPE * modify general user can't create,delete,update token (#3538) Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * [ui]Resource delete OK button to increase loading, change the number of homepage display cursor * fix * [Fix-3616][Server] when worker akc/response master exception , async retry (#3748) * [fixbug][ui]Repair the master and worker management instrument display * [Fix-3238][docker]Fix that can not create folder in docker with standalone mode (#3741) * [fixbug][ui]Remove non-existent or deleted resources disabled * [fixBug-3621][ui]If the workflow instance status is executing status, it is forbidden to select * [fix-3553][ui]Repair click workflow connection, select the entire path * fix * fix * [Fix-3238][docker]Fix that can not create folder in docker with standalone mode * [Fix-3616][Server] when worker akc/response master exception , async retry (#3776) * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> * The batch delete function in the workflow definition and workflow instance pages cannot be canceled if selected. * [Improvement-3720][ui] js mailbox verification fix * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect (#3784) * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * The batch delete function in the workflow definition and workflow instance pages cannot be canceled if selected. * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> * [Fix-3124][docker]Fix that can not build a docker image on windows (#3765) * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect (#3786) * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * The batch delete function in the workflow definition and workflow instance pages cannot be canceled if selected. * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> * [Fix-3258][Security][Worker group manage] Connot get create time and update time,report DateTimeParseException (#3787) * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * [Fix-3616][Server] when worker akc/response master exception , async retry * The batch delete function in the workflow definition and workflow instance pages cannot be canceled if selected. * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [Fix-3549] [Server][sqlTask]The alias column in the query SQL does not take effect * [BugFixed] issue #3258 (#3265) * 'ExecutionStatus' * '3258' * Update WorkerGroupServiceTest.java * Delete UserState.java * Delete ResourceSyncService.java * Delete core-site.xml * Delete hdfs-site.xml Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: qiaozhanwei <qiaozhanwei@outlook.com> Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> Co-authored-by: dailidong <dailidong66@gmail.com> * [fixBug-3792][ui]Click on the sidebar to adapt the width of the pie chart on the project homepage * [Bug-3713][HadoopUtils] catfile method Stream not closed (#3715) * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * dag add close button * reset last version * reset last version * dag add close buttion dag add close buttion * update CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * Update CreateWorkflowLocator.java modify submit workflow button * Update CreateWorkflowLocator.java * Update CreateWorkflowLocator.java modify CLICK_ADD_BUTTON * Update CreateWorkflowLocator.java delete print * Update CreateWorkflowLocator.java 1 * Update CreateWorkflowLocator.java 1 * Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dag.vue * Update dag.vue * Update dag.vue * Update CreateWorkflowLocator.java * Revert "Setting '-XX:+DisableExplicitGC ' causes netty memory leaks" This reverts commit3a2cba7a
* Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dolphinscheduler-daemon.sh * catfile method Stream not closed * catfile method Stream not closed Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> * [Fix-#3713][common]Fix that catfile method Stream not closed * [Fix-#3713][common]Fix that catfile method Stream not closed (#3810) * [Bug-3713][HadoopUtils] catfile method Stream not closed (#3715) * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * fix bug Delete invalid field: executorcores Modify verification prompt * dag add close button * reset last version * reset last version * dag add close buttion dag add close buttion * update CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * updae CLICK_SAVE_WORKFLOW_BUTTON xpath * Update CreateWorkflowLocator.java modify submit workflow button * Update CreateWorkflowLocator.java * Update CreateWorkflowLocator.java modify CLICK_ADD_BUTTON * Update CreateWorkflowLocator.java delete print * Update CreateWorkflowLocator.java 1 * Update CreateWorkflowLocator.java 1 * Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dag.vue * Update dag.vue * Update dag.vue * Update CreateWorkflowLocator.java * Revert "Setting '-XX:+DisableExplicitGC ' causes netty memory leaks" This reverts commit3a2cba7a
* Setting '-XX:+DisableExplicitGC ' causes netty memory leaks in addition update '- XX: largepagesizeinbytes = 128M' to '- XX: largepagesizeinbytes = 10M' * Update dolphinscheduler-daemon.sh * catfile method Stream not closed * catfile method Stream not closed Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> * [Fix-#3713][common]Fix that catfile method Stream not closed Co-authored-by: BoYiZhang <39816903+BoYiZhang@users.noreply.github.com> Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> * [Fix-#3487][api、dao] cherry pick from dev to fix that create folder duplicate name under multithreading * [Hotfix-3131][api] Fix the new tenant already exists prompt (#3132) * Bugfix: Fix the new tenant already exists prompt * Feature: Add test cases * Update TenantServiceTest.java Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: qiaozhanwei <qiaozhanwei@outlook.com> * Set up JDK 11 for SonarCloud in github action. (#3052) * Set up JDK 11 for SonarCloud in github action. * Fix javadoc error with JDK 11. * Prevent Javadoc from stopping if it finds any html errors. * [fixBug-3621][ui]Select the batch checkbox to unfilter the instances in the executing state * add verify tenant name cannot contain special characters. * [fixBug-3840][ui]The tenant code only allows letters or a combination of letters and numbers * fix * fix * fix * [Fix-#3702][api] When re-upload the resource file but don't change the name or desc,it need replace the origin resource file. (#3862) * [Fix-#3702][api] When re-upload the resource file but don't change the name or desc,it will not replace the origin resource file. * [Fix-#3702][api] When re-upload the resource file but don't change the name or desc,it will not replace the origin resource file. * [fixbug-3621][ui]Workflow instance ready to stop and ready to suspend state prohibits checking * [fixbug-3887][ui]Fix missing English translation of re-upload files * add process define name verify. (#3879) * Revert "[1.3.3-release][fix-3835][ui] When the tenantName contains "<", the tenant drop-down list is blankadd verify tenant name cannot contain special characters." * revert pr 3872 * [FIX-3617][Service]after subtask fault tolerance, 2 task instances are generated (#3830) * fix bug(#3617): after subtask fault tolerance, 2 task instances are generated. * delete unused code * update code smell * refactor sub work command process * add process service ut * add license header * fix some code smell * chang ut java8 to java11 * update sonar to java11 * copy ut config from dev * remove checkstyle * revert to 1.3.3 * change proess service test to executor service * add process service test * add process service test * revert * revert * add comments * change dev to 1.3.3-release * revert Co-authored-by: baoliang <baoliang@analysys.com.cn> * [Fix-#3487][sql] add dolphinscheduler_dml.sql under 1.3.3_schema (#3907) * [FIX-3836][1.3.3-release-API] process definition validation name interface prompt information error (#3899) * fix bug : error message * fix code smell * fix code smell * [FIX_#3789][remote]cherry pick from dev to support netty heart beat * [FIX_#3789][remote]cherry pick from dev to support netty heart beat * [FIX_#3789][remote]cherry pick from dev to support netty heart beat (#3913) * [FIX_#3789][remote]cherry pick from dev to support netty heart beat * [FIX_#3789][remote]cherry pick from dev to support netty heart beat Co-authored-by: Kirs <acm_master@163.com> * Repair check box cannot be canceled * [fix-3843][api] When update workflow definition,if name already exists, the prompt is not friendly * [fix-3843][api] When update workflow definition,if name already exists, the prompt is not friendly * [fix-#3843][api]When update workflow definition,if name already exists, the prompt is not friendly (#3918) * [FIX_#3789][remote]cherry pick from dev to support netty heart beat * [FIX_#3789][remote]cherry pick from dev to support netty heart beat * [fix-3843][api] When update workflow definition,if name already exists, the prompt is not friendly * [fix-3843][api] When update workflow definition,if name already exists, the prompt is not friendly Co-authored-by: Kirs <acm_master@163.com> * [Fix-#3487][sql] update uc_dolphin_T_t_ds_resources_un * Workflow definition name re-modified and added check * [fix-#3843][api]When update workflow definition,if name already exists, the prompt is not friendly. * update code. * [#3931][ui]Field name optimization for spark, flink, and mr * change version from 1.3.2-SNAPSHOT to 1.3.3-SNAPSHOT (#3934) * [maven-release-plugin] prepare release 1.3.3 * [maven-release-plugin] prepare for next development iteration * [ambari-plugin]change version 1.3.2 to 1.3.3 (#3935) * fix bug:3615 After the task is executed successfully, but the next task has not been submitted, stop the master * [fixBug-3964][ui]Switch back and forth over timeout alarm, the selected value is empty * solve too many files, close logClientService (#3971) * fix #3966 sub process doesnot send alert mail after process instance ending. (#3972) Co-authored-by: baoliang <baoliang@analysys.com.cn> * [Fix-#3618][server] resolve task executed finished but not release the file handle (#3975) * [Fix-#3618][server] resolve task executed finished but not release the file handle * [Fix-#3618][server] resolve task executed finished but not release the file handle * [Fix-#3958][api] files should not be created successfully in the directory of the authorized file * [FIX-3966] The timeout warning does not take effect in sub_process (#3982) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent Co-authored-by: baoliang <baoliang@analysys.com.cn> * fix import dolphinscheduler_mysql.sql insert admin user data * [FIX-3929] condition task would post wrong tasks when failover. (#3999) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent * remove stdout in logback configuration * fix bug #3929 condition task would post error when failover. * remove unused test * add comments * add skip node judge Co-authored-by: baoliang <baoliang@analysys.com.cn> * [FIX-3929] because of no lock, start up failover would dispatch two same tasks. (#4004) * fix #3966 sub process doesnot send alert mail after process instance ending. * fix bug 3964: sub_process The timeout warning does not take effect add timeout warning for sub_process/dependent task. * fix code smell * fix code smell * fix code smell * update worker group inherit from parent * remove stdout in logback configuration * fix bug #3929 condition task would post error when failover. * remove unused test * add comments * add skip node judge * fix bug 3929: because of no lock, start up failover would dispatch two same tasks. Co-authored-by: baoliang <baoliang@analysys.com.cn> * revert pom version to 1.3.3-release * [maven-release-plugin] prepare release 1.3.3 * [maven-release-plugin] prepare for next development iteration * [release]revert pom version to 1.3.3-release * fix bug 4010: remove failed condition tasks from error-task-list. (#4011) Co-authored-by: baoliang <baoliang@analysys.com.cn> * [maven-release-plugin] prepare release 1.3.3 * [maven-release-plugin] prepare for next development iteration * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor code style * refactor code style * refactor code style * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor ut test * refactor ut test * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor ut * merge from 1.3.3-release * refactor ut * refactor ut * refactor * refactor * refactor code style * refactor code style * refactor code style * refactor code style * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * merge from 1.3.3-release * refactor code style Co-authored-by: break60 <790061044@qq.com> Co-authored-by: wuchunfu <319355703@qq.com> Co-authored-by: lgcareer <18610854716@163.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> Co-authored-by: lenboo <baoliang@analysys.com.cn> Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: Yelli <amarantine@my.com> Co-authored-by: Eights-Li <yelli.hl@gmail.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: qiaozhanwei <qiaozhanwei@outlook.com> Co-authored-by: XiaotaoYi <v-xiayi@hotmail.com> Co-authored-by: Yichao Yang <1048262223@qq.com> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: BoYiZhang <39816903+BoYiZhang@users.noreply.github.com> Co-authored-by: muzhongjiang <mu_zhongjiang@163.com> Co-authored-by: Jave-Chen <baicai.chen@gmail.com> Co-authored-by: zhuangchong <zhuangchong6@163.com> Co-authored-by: zhuangchong <37063904+zhuangchong@users.noreply.github.com> Co-authored-by: Kirs <acm_master@163.com> Co-authored-by: lgcareer <lgcareer@apache.org> Co-authored-by: wulingqi <wulingqi@baijiahulian.com> * Revert "[Draft][Merge][133-dev]133 merge dev (#4031)" (#4057) This reverts commitad2d9f99d0
. * [Fix][API] Condition task null pointer exception (#4056) * add ProcessUtils UT * modify ProcessUtils & ProcessUtilsTest * Enhance user experience, add close button, return to the previous page (#4006) Co-authored-by: zhanglong <zhanglong@ysstech.com> * [FIX_BUG][server-test] dismiss of server warm-up time in RoundRobinSelectorTest (#4067) * [Fix][api] Fix build parameter error of sqlserver when create. (#4015) * [fix-#3962][api] Avoid ClassCastException for LoggerService.queryLog(). * [Fix][api] Fix build parameter error of sqlserver when create. * [Feature-3985][Datax] Datax supports setting up running memory (#3986) * Datax supports setting up running memory * Datax supports setting up running memory * Datax supports setting up running memory * When running a task, the resource file is lost, which results in an error * add unit test * add unit test * add unit test * add test unit * add test unit * add test unit * fix code smell * add test unit * add test unit * [Improvement-3767][api] Task instance supports query by process instance name (#3825) * Task instance supports query by process instance name. * add test code checkstyle. * add test param. * resolve the sonar duplication check. * solve logger single-line string exceeds 200 characters. * resolve the sonar check. * Resolve code conflicts. Co-authored-by: zhuangchong <zhuangchong8@163.com> * deal with magic value * [Feature-4050][server] Spark task support udv inject (#4061) * #4050 spark task support udv inject * modify spark task UT * modify sparkTaskExecutionCtx * add exp for spark task get main jar method * deal with magic value * [Improvement-3471][common] JSONUtils.toMap It is not necessary to check whether the JSON method is empty again. #3471 (#3481) * JSONUtils.toMap call improvement. * [Fix-4054][Api] Fix The last week of the month for adding/editing timing, preview and save timing will report an error * 解决单独执行子节点空指针的问题 * using OSUtils.execCmd when kill yarn app * 解决单独执行子节点空指针的问题(增加checkstyle) * 解决单独执行子节点空指针的问题(增加checkstyle) * [FIX-#4083][server]fix taskInstance state change error Concurrent processing of ack message and result message causes the execution sequence to be wrong # this close # 4083 * code style * fix replaceNRTtoUnderline NullPointerException #4098 (#4100) * fix replaceNRTtoUnderline NullPointerException * add unit Test * add taskResponseTest * add taskResponseTest * code smell * Time is too small and the task is not finished * Time is too small and the task is not finished * [FIX-4034][server] fix sqoop import fail (#4036) * fix #4043, sqoop import query fail * fix #4043, sqoop task hard code & code style * add license for SqoopConstants * add private constructor for SqoopConstants * fixed sqoop mysql pwd have special character * fix checkstyle * fix sqoop task log * remove unused constants * Time is too small and the task is not finished * Time is too small and the task is not finished * test * remove assert * test * test * fix task instance status judgment error * fix: security page disappear delay problem when force refresh under GENERAL_USER * improvement: resovle download url with resolveURL to prevent change of apiPrefix * fix sqoop task jdbc string contains special char (#4105) * [Bug][Common] read file garbled (#3479) * fix bug : Random code problem Co-authored-by: zhanglong <zhanglong@ysstech.com> * [Improvement-3933][db operation] Improve the performance of sql query (#3940) * optimize select * case * emove redundancy * bug fixed * Update en_US.js * Update startup.sh * optimize * optimize code * optimize * bug fixed * add ut * bug fixed * bug fixed * bug fixed * bug fixed * Delete WorkFlowLineageMapper.xml * Delete createTenement.vue * recove wrongly deleted file * Update WorkFlowLineageMapper.xml * Update createTenement.vue * [Feature][API]enable response resources gzip compression (#4121) * enable response compression * add server.compression.mime-types with default value explicitly * [Improvement][API] ignore noNodeException when get worker groups (#4120) * ignore noNodeException when get worker groups * add ut * [Improvement][Code style] FIX SPELL WAITTING TO WAITING , etc. (#4118) * FIX SPELL * FIX SPELL AND Optimizing code conventions * add ut cannot construct process instance, return null; * add ut testExportProcessMetaData * add ut testExportProcessMetaData * add ut testImportProcessSchedule * add ut MasterExecThreadTest * add ut MasterExecThreadTest * add ut testSubProcessViewTree * add ut testComplementWithStartNodeList * add ut testRecurseFindSubProcessId * add ut testRecurseFindSubProcessId * add ut testRecurseFindSubProcessId * [FIX#4033] $[] conflicts with mysql keywords (#4111) * [FIX#4033] $[] conflicts with mysql keywords We currently only use this symbol for dates, so I filtered out the number type. this close #4033 * test * fix error * split sqoop import hive database and table (#4141) * upgrade quartz version to 2.3.0 * add HikariCP-java6,c3p0,mchange-commons-java license * upgrade jackson version to 2.9.10 * remove c3p0,mchange-commons-java license * update Check code style * update code style * Update pom.xml * Update pom.xml * Update LICENSE not need to add HikariCP-java6 * Delete LICENSE-HikariCP-java6.txt * Update known-dependencies.txt * Update TaskInstanceMapper.xml optimize page of [TaskInstance] load data slow * [FIX-PR-4097][server-master]task ack miss (#4189) When the message of successful execution arrives earlier than the message of ack, the message of ack will be discarded, resulting in some information missing * fix bug #4125 (#4127) * fix bug #4125 * code style! * code style. Co-authored-by: chengp <chengp@chengp.net> * [FIX-4190][DAO] When the amount of json data is large, the process list page display slowly. (#4201) * fix 4190: When the amount of json data is large, process list page display slowly * fix 4190: When the amount of json data is large, process list page display slowly * fix 4190: When the amount of json data is large, process list page display slowly Co-authored-by: baoliang <baoliang@analysys.com.cn> * [Fix-3457][flink] fix flink args build problem (#4166) * [Fix][Flink] fix flink args build problem * [Fix][Flink] fix FlinkArgsUtilsTest * [Improvement][UI] hide version and cluster input when deployMode is local * [common]del windows file( not support windows ) (#4204) * del support win * del support win * [Feature-4138][Master] dispatch workgroup error add sleep time (#4139) * When there are tasks with assignment failure and the number of tasks in the current task queue is less than 10, sleep for 1 second * When there are tasks with assignment failure and the number of tasks in the current task queue is less than 10, sleep for 1 second * fix code smell & code style * fix code smell & code style Co-authored-by: zhanglong <zhanglong@ysstech.com> * [FIX-#4172][server-worker] kill task NPE (#4182) * [FIX-#4172][server-worker] kill task NPE The cache task will be sent when the Process is generated. Before that, if a kill task appears, then NPE will appear Modification method: write into the cache when the task is received, and mark it as preData If the task is killed before the Process is generated, delete the cache directly at this time It will be judged before the process is generated. If the task has been killed, it will not be executed. After the new process is created, write it into the cache, and judge again, if kill, then kill the process. this closes #4172 * Delete the commented out code Add spring beans * code smell * add test * add test * fix error * test * test * revert * fix error * [Feature-3878]Replace the page with element-ui (#4065) * [Feature-3878]Introduce elment-ui and replace the security center module page with elment-ui * Change node version * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * Replace the page with element-ui * Replace user management with elment-ui * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * fix * Repair the last Sunday of each month * support auto eslint for .js, .vue file on save * update .eslintrc.yml and license check exclude .eslintignore * fix eslint: fix syntax by npm run lint automatically * fix eslint: fatal syntax errors * fix eslint: expected '!==' but instead saw '!=', expected '===' but instead saw '==' * fix eslint: Unexpected side effect in 'cacheParams' computed property * fix eslint: assigned a value but never used * fix eslint: component has been registered but not used * fix eslint: unexpected mutation of prop * fix bug: start from the setting nodes with NODE_PRE would be NPE. (#4219) * deleted invalid code as assigned in issue 4215 (#4221) deleted the code at following two places: org.apache.dolphinscheduler.service.process.ProcessService#checkTaskExistsInTaskQueue org.apache.dolphinscheduler.service.process.ProcessService#taskZkInfo * [FIX-#3177]Task time parameter parsing error (#4224) * [FIX-#3177]Task time parameter parsing error rerun schedule time error this closes #3177 * [FIX-#3177]Task time parameter parsing error rerun schedule time error this closes #3177 * fix sql error (#4227) * [FIX-3177]Task time parameter parsing error (#4228) * [FIX-3177]Task time parameter parsing error when system.datetime !=null $[datetime] = system.datetime else $[datetime] = current time * remove unused import * fix date_convert null * fix time cover * fix time cover * reformat * add ut * [Fix][UI]: fix re-login problem in new tab and state synchronization problem in multiple tabs (#4162) * fix(ui): re-login problem in new tab * refresh page in new tab automatically * support to reload router view in lightweight * optimize visibility code * [Improvement][UI] Add no-var rule for eslint and add 'npm run lint:fix' command (#4225) Add no-var rule for eslint, and fix related files Add npm run lint:fix command, which distinguished from the default command npm run lint The behavior of command npm run lint and command npm run lint:fix should be distinguished The first command is used to lint only, and the second one is used to lint and fix problems automatically * [FIX][UI ] security user state tenantCode User Type Display abnormal (#4255) * fix user state error * fix userType error * fix tenantCode error * [Fix-4222][Master]Add the priority queue to ensure that tasks are submitted according to priority. (#4250) * [Fix-4222][Master]Add the priority queue to ensure that tasks are submitted according to priority. * [Fix-4222][Master]Add the priority queue to ensure that tasks are submitted according to priority. * [Fix-4222][Master]Remove useless import * [Fix-4222][Master]Reformat code style * [Fix-4222][Master]Reformat code style * [Fix-4222][Master]Reformat code style * [Fix-4222][Master]add PeerTaskInstancePriorityQueueTest * [Fix-4222][Master]Fix code smell * [Fix-4222][Master]Reformat code style * [Fix-4222][Master]Fix code smell Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> * update bug template (#4260) * [Improvement-4069][server] When the tenant does not exist, the task execution should throw an exception (#4108) * when the tenant does not exist, the task execution should throw an exception * remote method createWorkDirAndUserIfAbsent * set the task status failed when the tenant code does not exist. * add taskLog. * update check os user exists * update TaskExecuteThreadTest test method. * solving sonar fail. * remove AbstractTask.getCurTaskParamsClass()and replace with TaskParametersUtils.getParameters() (#4262) * remove getCurTaskParamsClass() in AbstractTask.java and replace it with TaskParametersUtils.getParameters() * remove unused imports in AbstractTask.java * reformat * [Fix-4271][server] Fix IOException or NoSuchFileException in logger server (#4272) * fix version funcation delete. (#4265) * [improvement][config] Update datasource.properties,add mysql meta data template (#4266) * Update datasource.properties [新增]元数据mysql连接模版 * Update datasource.properties Co-authored-by: dailidong <dailidong66@gmail.com> * fix taskInstance submitTime is empty. (#4274) * [Improvement-3878]Tenant list delete user name (#4278) * [Fix-4268] Fix NumberFormatException when visiting a doc.html or swagger-ui.html (#4269) * [Fix-4268] Fix NumberFormatException when visiting a doc.html or swagger-ui.html * Fix checkstyle error * Update swagger-models in known-dependencies.txt * [Improvement-3878][ui]Fix the list style (#4280) * [Improvement-3878]Tenant list delete user name * [Improvement-3878][ui]Fix the list style * [FIX] [UI] fix create project cancel button invalid (#4282) * fix create project cancel button invalid * [Improvement] Refactor code to support distributed tracing (#4270) * Refactor code to support tracing * Extension network protocol, support context and version * Extension master asynchronous queue support context * Extract scan task method from MasterSchedulerService for tracing * fix * fix * add test case * fix * fix Co-authored-by: hailin0 <hailin0@yeah.net> * [Improvement] Add Flink job name (#4285) * [Improvement] Add Flink job name * fix typo * [Improvement][ui]List vacancy optimization and icon icon repair (#4286) * [Improvement][ui] List vacancy optimization and icon icon repair * [FEATURE-736] integrate ldap authentication (#3743) * [FEATURE-736] integrate ldap authentication * add ldap authentication type * refactor authentication with ldap and password * add createUser for ldap in user service * remove duplicate password authenticator * [Fix-4289][*] Flink name with disappeared and unescaped problem (#4290) * fix flink name not display in process definition editor * fix flink name not escape problem * simplify escape method * fix database is the mysql DB keyword. (#4295) * fix the token management list does not display the user name. (#4302) * Dev imp server process utils (#4263) * Adds the comment on the WINDOWSATTERN Co-authored-by: Kirs <acm_master@163.com> Co-authored-by: 0002939 <licongyang@mininglamp.com> * fix version close function does not take effect. (#4307) * fix user management authorization operation exceptions do not prompt exception information. (#4292) * [Fix][UI] Fix ui style problem and refactor form style (#4329) * rename from-model to form-model * [UI] remove duplicated css style code * [UI] refactor css style of form model * fix form model overflow problem in ie * Align each item one by one in locale * fix el-dialog width is too wide * fix locale * [Improvement][UI] Improve script box and dialog css style (#4331) * [Fix-4335][UI] Fix IE 9-11 not supported * [FIx-4338][UI] Fix invalid date problem in IE * [Improvement] Use environment variable $DOLPHINSCHEDULE_OPTS as daemon startup arguments (#4341) Co-authored-by: hailin0 <hailin0@yeah.net> * [Fix][common] only two yarns can be selected(#4314) (#4344) * Handling conflicts manually * code style * ut skip ui * fix ut error * fix ut error * delete SchedulerController Unused field * delete SchedulerController Unused field * delete SchedulerController Unused field * ci skip ui * ignore AlertPluginManagerTest.java and DolphinPluginLoaderTest.java * fix ut error * fix ut error * test * code style * replace ui * replace ui * replace ui * replace ui * fix license * fix license Co-authored-by: 小清 <62982788+597365581@users.noreply.github.com> Co-authored-by: zhuangchong <37063904+zhuangchong@users.noreply.github.com> Co-authored-by: spring-bu <37682426+spring-bu@users.noreply.github.com> Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: lgcareer <18610854716@163.com> Co-authored-by: BoYiZhang <39816903+BoYiZhang@users.noreply.github.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> Co-authored-by: baoliang <baoliang@analysys.com.cn> Co-authored-by: BoYiZhang <zhangboyi_mx@163.com> Co-authored-by: zixi0825 <649790970@qq.com> Co-authored-by: sunchaohe <sunzhaohe@linklogis.com> Co-authored-by: break60 <790061044@qq.com> Co-authored-by: bao liang <29528966+lenboo@users.noreply.github.com> Co-authored-by: t1mon <178317391@qq.com> Co-authored-by: zhanglong <zhanglong@ysstech.com> Co-authored-by: 孙继峰 <sun.jifeng@outlook.com> Co-authored-by: wulingqi <wulingqi@baijiahulian.com> Co-authored-by: lgcareer <lgcareer@apache.org> Co-authored-by: IamMujuziMoses <49279842+IamMujuziMoses@users.noreply.github.com> Co-authored-by: huzekang <1040080742@qq.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> Co-authored-by: Eights-LI <yelli.eights@gmail.com> Co-authored-by: wuchunfu <319355703@qq.com> Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: Yelli <amarantine@my.com> Co-authored-by: Eights-Li <yelli.hl@gmail.com> Co-authored-by: qiaozhanwei <qiaozhanwei@outlook.com> Co-authored-by: XiaotaoYi <v-xiayi@hotmail.com> Co-authored-by: Yichao Yang <1048262223@qq.com> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: muzhongjiang <mu_zhongjiang@163.com> Co-authored-by: Jave-Chen <baicai.chen@gmail.com> Co-authored-by: zhuangchong <zhuangchong6@163.com> Co-authored-by: hailin0 <hailin0@yeah.net> Co-authored-by: yangquan <iyeeku@qq.com> Co-authored-by: liliang1991 <liliang_68@126.com> Co-authored-by: liang.li.c <liang.li.c@17zuoye.com> Co-authored-by: felix.wang <59079269+felix-thinkingdata@users.noreply.github.com> Co-authored-by: chengshiwen <chengshiwen0103@gmail.com> Co-authored-by: Yarlung <turingdojo@163.com> Co-authored-by: karlsun <karlsun@tencent.com> Co-authored-by: wangxj3 <857234426@qq.com> Co-authored-by: chengp <5058557@qq.com> Co-authored-by: chengp <chengp@chengp.net> Co-authored-by: Saksham Gupta <saksham1319@gmail.com> Co-authored-by: Tq <36755957+Tianqi-Dotes@users.noreply.github.com> Co-authored-by: Jatham <59549328+Jatham922@users.noreply.github.com> Co-authored-by: hailin0 <hailin0@foxmail.com> Co-authored-by: zh0122 <zh0122@gmail.com> Co-authored-by: geosmart <geosmart@hotmail.com> Co-authored-by: 李丛阳 <liby-1987@163.com> Co-authored-by: 0002939 <licongyang@mininglamp.com> Co-authored-by: kamisamak <1057372918@qq.com> * fix alert-spi error todo sql script * add page query plugin instance add plugin instance check name * add page query plugin instance add plugin instance check name * add props field * ding talk some filed is not required * fix bug * fix error * revert * add name field provide to ui * fix send error * add ui * delete useless constant definitions code style * code style * fix license head error * fix ut error * fix ut error * del unused jar * import alert-plugin * upgrade jboss-logging * upgrade jboss-logging * fix ut error * fix Vulnerabilities * fix Vulnerabilities * fix Vulnerabilities * code smell * fix Vulnerabilities * add public constructors * fix Vulnerabilities * resolve conflicts Co-authored-by: break60 <790061044@qq.com> Co-authored-by: gaojun2048 <32193458+gaojun2048@users.noreply.github.com> Co-authored-by: zhuangchong <zhuangchong6@163.com> Co-authored-by: dailidong <dailidong66@gmail.com> Co-authored-by: samz406 <samz406@foxmail.com> Co-authored-by: gaojun2048 <540957506@qq.com> Co-authored-by: zhuangchong <37063904+zhuangchong@users.noreply.github.com> Co-authored-by: Yichao Yang <1048262223@qq.com> Co-authored-by: 小清 <62982788+597365581@users.noreply.github.com> Co-authored-by: spring-bu <37682426+spring-bu@users.noreply.github.com> Co-authored-by: lgcareer <18610854716@163.com> Co-authored-by: BoYiZhang <39816903+BoYiZhang@users.noreply.github.com> Co-authored-by: xingchun-chen <55787491+xingchun-chen@users.noreply.github.com> Co-authored-by: baoliang <baoliang@analysys.com.cn> Co-authored-by: BoYiZhang <zhangboyi_mx@163.com> Co-authored-by: zixi0825 <649790970@qq.com> Co-authored-by: sunchaohe <sunzhaohe@linklogis.com> Co-authored-by: bao liang <29528966+lenboo@users.noreply.github.com> Co-authored-by: t1mon <178317391@qq.com> Co-authored-by: zhanglong <zhanglong@ysstech.com> Co-authored-by: 孙继峰 <sun.jifeng@outlook.com> Co-authored-by: wulingqi <wulingqi@baijiahulian.com> Co-authored-by: lgcareer <lgcareer@apache.org> Co-authored-by: IamMujuziMoses <49279842+IamMujuziMoses@users.noreply.github.com> Co-authored-by: huzekang <1040080742@qq.com> Co-authored-by: JinyLeeChina <42576980+JinyLeeChina@users.noreply.github.com> Co-authored-by: Eights-LI <yelli.eights@gmail.com> Co-authored-by: wuchunfu <319355703@qq.com> Co-authored-by: qiaozhanwei <qiaozhanwei@analysys.com.cn> Co-authored-by: Yelli <amarantine@my.com> Co-authored-by: Eights-Li <yelli.hl@gmail.com> Co-authored-by: qiaozhanwei <qiaozhanwei@outlook.com> Co-authored-by: XiaotaoYi <v-xiayi@hotmail.com> Co-authored-by: zhuangchong <zhuangchong8@163.com> Co-authored-by: muzhongjiang <mu_zhongjiang@163.com> Co-authored-by: Jave-Chen <baicai.chen@gmail.com> Co-authored-by: hailin0 <hailin0@yeah.net> Co-authored-by: yangquan <iyeeku@qq.com> Co-authored-by: liliang1991 <liliang_68@126.com> Co-authored-by: liang.li.c <liang.li.c@17zuoye.com> Co-authored-by: felix.wang <59079269+felix-thinkingdata@users.noreply.github.com> Co-authored-by: chengshiwen <chengshiwen0103@gmail.com> Co-authored-by: Yarlung <turingdojo@163.com> Co-authored-by: karlsun <karlsun@tencent.com> Co-authored-by: wangxj3 <857234426@qq.com> Co-authored-by: chengp <5058557@qq.com> Co-authored-by: chengp <chengp@chengp.net> Co-authored-by: Saksham Gupta <saksham1319@gmail.com> Co-authored-by: Tq <36755957+Tianqi-Dotes@users.noreply.github.com> Co-authored-by: Jatham <59549328+Jatham922@users.noreply.github.com> Co-authored-by: hailin0 <hailin0@foxmail.com> Co-authored-by: zh0122 <zh0122@gmail.com> Co-authored-by: geosmart <geosmart@hotmail.com> Co-authored-by: 李丛阳 <liby-1987@163.com> Co-authored-by: 0002939 <licongyang@mininglamp.com> Co-authored-by: kamisamak <1057372918@qq.com>
Kirs
4 years ago
committed by
GitHub
237 changed files with 12419 additions and 6087 deletions
@ -0,0 +1,25 @@ |
|||||||
|
# |
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
# contributor license agreements. See the NOTICE file distributed with |
||||||
|
# this work for additional information regarding copyright ownership. |
||||||
|
# The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
# (the "License"); you may not use this file except in compliance with |
||||||
|
# the License. You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
# |
||||||
|
dependencies: |
||||||
|
- name: postgresql |
||||||
|
version: 8.x.x |
||||||
|
repository: https://charts.bitnami.com/bitnami |
||||||
|
condition: postgresql.enabled |
||||||
|
- name: zookeeper |
||||||
|
version: 5.x.x |
||||||
|
repository: https://charts.bitnami.com/bitnami |
||||||
|
condition: redis.enabled |
@ -0,0 +1,25 @@ |
|||||||
|
# |
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
# contributor license agreements. See the NOTICE file distributed with |
||||||
|
# this work for additional information regarding copyright ownership. |
||||||
|
# The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
# (the "License"); you may not use this file except in compliance with |
||||||
|
# the License. You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
# |
||||||
|
dependencies: |
||||||
|
- name: postgresql |
||||||
|
version: 8.x.x |
||||||
|
repository: https://charts.bitnami.com/bitnami |
||||||
|
condition: postgresql.enabled |
||||||
|
- name: zookeeper |
||||||
|
version: 5.x.x |
||||||
|
repository: https://charts.bitnami.com/bitnami |
||||||
|
condition: redis.enabled |
@ -0,0 +1,82 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-alert-dingtalk</artifactId> |
||||||
|
<packaging>dolphinscheduler-plugin</packaging> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-spi</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||||
|
<artifactId>httpclient</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>slf4j-api</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-annotations</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<type>jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>dolphinscheduler-alert-dingtalk-${project.version}</finalName> |
||||||
|
</build> |
||||||
|
|
||||||
|
</project> |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkAlertChannel |
||||||
|
*/ |
||||||
|
public class DingTalkAlertChannel implements AlertChannel { |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertResult process(AlertInfo alertInfo) { |
||||||
|
|
||||||
|
AlertData alertData = alertInfo.getAlertData(); |
||||||
|
String alertParams = alertInfo.getAlertParams(); |
||||||
|
Map<String, String> paramsMap = PluginParamsTransfer.getPluginParamsMap(alertParams); |
||||||
|
return new DingTalkSender(paramsMap).sendDingTalkMsg(alertData.getTitle(), alertData.getContent()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PasswordParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.RadioParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkAlertChannelFactory |
||||||
|
*/ |
||||||
|
public class DingTalkAlertChannelFactory implements AlertChannelFactory { |
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "DingTalk"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<PluginParams> getParams() { |
||||||
|
InputParam webHookParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, DingTalkParamsConstants.DING_TALK_WEB_HOOK) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
InputParam keywordParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, DingTalkParamsConstants.DING_TALK_KEYWORD) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
RadioParam isEnableProxy = |
||||||
|
RadioParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE) |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.setValue(true) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(false) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
InputParam proxyParam = |
||||||
|
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY, DingTalkParamsConstants.DING_TALK_PROXY) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(false).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam portParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PORT, DingTalkParamsConstants.DING_TALK_PORT) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(false).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam userParam = |
||||||
|
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_USER, DingTalkParamsConstants.DING_TALK_USER) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(false).build()) |
||||||
|
.build(); |
||||||
|
PasswordParam passwordParam = PasswordParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, DingTalkParamsConstants.DING_TALK_PASSWORD) |
||||||
|
.setPlaceholder("if enable use authentication, you need input password") |
||||||
|
.build(); |
||||||
|
|
||||||
|
return Arrays.asList(webHookParam, keywordParam, isEnableProxy, proxyParam, portParam, userParam, passwordParam); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertChannel create() { |
||||||
|
return new DingTalkAlertChannel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkAlertPlugin |
||||||
|
*/ |
||||||
|
public class DingTalkAlertPlugin implements DolphinSchedulerPlugin { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterable<AlertChannelFactory> getAlertChannelFactorys() { |
||||||
|
return ImmutableList.of(new DingTalkAlertChannelFactory()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkParamsConstants |
||||||
|
*/ |
||||||
|
public class DingTalkParamsConstants { |
||||||
|
|
||||||
|
public DingTalkParamsConstants() { |
||||||
|
throw new IllegalStateException("Utility class"); |
||||||
|
} |
||||||
|
|
||||||
|
static final String DING_TALK_WEB_HOOK = "dingtalk.webhook"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_WEB_HOOK = "dingTalkWebHook"; |
||||||
|
|
||||||
|
static final String DING_TALK_KEYWORD = "dingtalk.keyword"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_KEYWORD = "dingTalkKeyword"; |
||||||
|
|
||||||
|
public static final String DING_TALK_PROXY_ENABLE = "dingtalk.isEnableProxy"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_PROXY_ENABLE = "dingTalkIsEnableProxy"; |
||||||
|
|
||||||
|
static final String DING_TALK_PROXY = "dingtalk.proxy"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_PROXY = "dingTalkProxy"; |
||||||
|
|
||||||
|
static final String DING_TALK_PORT = "dingtalk.port"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_PORT = "dingTalkPort"; |
||||||
|
|
||||||
|
static final String DING_TALK_USER = "dingtalk.user"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_USER = "dingTalkUser"; |
||||||
|
|
||||||
|
static final String DING_TALK_PASSWORD = "dingtalk.password"; |
||||||
|
|
||||||
|
static final String NAME_DING_TALK_PASSWORD = "dingTalkPassword"; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,204 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.StringUtils; |
||||||
|
import org.apache.http.HttpEntity; |
||||||
|
import org.apache.http.HttpHost; |
||||||
|
import org.apache.http.auth.AuthScope; |
||||||
|
import org.apache.http.auth.UsernamePasswordCredentials; |
||||||
|
import org.apache.http.client.CredentialsProvider; |
||||||
|
import org.apache.http.client.config.RequestConfig; |
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse; |
||||||
|
import org.apache.http.client.methods.HttpPost; |
||||||
|
import org.apache.http.entity.StringEntity; |
||||||
|
import org.apache.http.impl.client.BasicCredentialsProvider; |
||||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||||
|
import org.apache.http.impl.client.HttpClients; |
||||||
|
import org.apache.http.util.EntityUtils; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ding Talk Sender |
||||||
|
*/ |
||||||
|
public class DingTalkSender { |
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DingTalkSender.class); |
||||||
|
|
||||||
|
private String url; |
||||||
|
|
||||||
|
private String keyword; |
||||||
|
|
||||||
|
private Boolean enableProxy; |
||||||
|
|
||||||
|
private String proxy; |
||||||
|
|
||||||
|
private Integer port; |
||||||
|
|
||||||
|
private String user; |
||||||
|
|
||||||
|
private String password; |
||||||
|
|
||||||
|
DingTalkSender(Map<String, String> config) { |
||||||
|
url = config.get(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK); |
||||||
|
keyword = config.get(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD); |
||||||
|
enableProxy = Boolean.valueOf(config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE)); |
||||||
|
if (Boolean.TRUE.equals(enableProxy)) { |
||||||
|
port = Integer.parseInt(config.get(DingTalkParamsConstants.NAME_DING_TALK_PORT)); |
||||||
|
proxy = config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY); |
||||||
|
user = config.get(DingTalkParamsConstants.DING_TALK_USER); |
||||||
|
password = config.get(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public AlertResult sendDingTalkMsg(String msg, String charset) { |
||||||
|
AlertResult alertResult; |
||||||
|
try { |
||||||
|
String resp = sendMsg(msg, charset); |
||||||
|
return checkSendDingTalkSendMsgResult(resp); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.info("send ding talk alert msg exception : {}", e.getMessage()); |
||||||
|
alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
alertResult.setMessage("send ding talk alert fail."); |
||||||
|
} |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
private String sendMsg(String msg, String charset) throws IOException { |
||||||
|
|
||||||
|
String msgToJson = textToJsonString(msg + "#" + keyword); |
||||||
|
HttpPost httpPost = constructHttpPost(url, msgToJson, charset); |
||||||
|
|
||||||
|
CloseableHttpClient httpClient; |
||||||
|
if (Boolean.TRUE.equals(enableProxy)) { |
||||||
|
httpClient = getProxyClient(proxy, port, user, password); |
||||||
|
RequestConfig rcf = getProxyConfig(proxy, port); |
||||||
|
httpPost.setConfig(rcf); |
||||||
|
} else { |
||||||
|
httpClient = getDefaultClient(); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
CloseableHttpResponse response = httpClient.execute(httpPost); |
||||||
|
String resp; |
||||||
|
try { |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
resp = EntityUtils.toString(entity, charset); |
||||||
|
EntityUtils.consume(entity); |
||||||
|
} finally { |
||||||
|
response.close(); |
||||||
|
} |
||||||
|
logger.info("Ding Talk send [ %s ], resp:{%s}", msg, resp); |
||||||
|
return resp; |
||||||
|
} finally { |
||||||
|
httpClient.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static HttpPost constructHttpPost(String url, String msg, String charset) { |
||||||
|
HttpPost post = new HttpPost(url); |
||||||
|
StringEntity entity = new StringEntity(msg, charset); |
||||||
|
post.setEntity(entity); |
||||||
|
post.addHeader("Content-Type", "application/json; charset=utf-8"); |
||||||
|
return post; |
||||||
|
} |
||||||
|
|
||||||
|
private static CloseableHttpClient getProxyClient(String proxy, int port, String user, String password) { |
||||||
|
HttpHost httpProxy = new HttpHost(proxy, port); |
||||||
|
CredentialsProvider provider = new BasicCredentialsProvider(); |
||||||
|
provider.setCredentials(new AuthScope(httpProxy), new UsernamePasswordCredentials(user, password)); |
||||||
|
return HttpClients.custom().setDefaultCredentialsProvider(provider).build(); |
||||||
|
} |
||||||
|
|
||||||
|
private static CloseableHttpClient getDefaultClient() { |
||||||
|
return HttpClients.createDefault(); |
||||||
|
} |
||||||
|
|
||||||
|
private static RequestConfig getProxyConfig(String proxy, int port) { |
||||||
|
HttpHost httpProxy = new HttpHost(proxy, port); |
||||||
|
return RequestConfig.custom().setProxy(httpProxy).build(); |
||||||
|
} |
||||||
|
|
||||||
|
private static String textToJsonString(String text) { |
||||||
|
Map<String, Object> items = new HashMap<>(); |
||||||
|
items.put("msgtype", "text"); |
||||||
|
Map<String, String> textContent = new HashMap<>(); |
||||||
|
byte[] byt = StringUtils.getBytesUtf8(text); |
||||||
|
String txt = StringUtils.newStringUtf8(byt); |
||||||
|
textContent.put("content", txt); |
||||||
|
items.put("text", textContent); |
||||||
|
return JSONUtils.toJsonString(items); |
||||||
|
} |
||||||
|
|
||||||
|
public static class DingTalkSendMsgResponse { |
||||||
|
private Integer errcode; |
||||||
|
private String errmsg; |
||||||
|
|
||||||
|
public Integer getErrcode() { |
||||||
|
return errcode; |
||||||
|
} |
||||||
|
|
||||||
|
public void setErrcode(Integer errcode) { |
||||||
|
this.errcode = errcode; |
||||||
|
} |
||||||
|
|
||||||
|
public String getErrmsg() { |
||||||
|
return errmsg; |
||||||
|
} |
||||||
|
|
||||||
|
public void setErrmsg(String errmsg) { |
||||||
|
this.errmsg = errmsg; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static AlertResult checkSendDingTalkSendMsgResult(String result) { |
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
|
||||||
|
if (null == result) { |
||||||
|
alertResult.setMessage("send ding talk msg error"); |
||||||
|
logger.info("send ding talk msg error,ding talk server resp is null"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
DingTalkSendMsgResponse sendMsgResponse = JSONUtils.parseObject(result, DingTalkSendMsgResponse.class); |
||||||
|
if (null == sendMsgResponse) { |
||||||
|
alertResult.setMessage("send ding talk msg fail"); |
||||||
|
logger.info("send ding talk msg error,resp error"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
if (sendMsgResponse.errcode == 0) { |
||||||
|
alertResult.setStatus("true"); |
||||||
|
alertResult.setMessage("send ding talk msg success"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
alertResult.setMessage(String.format("alert send ding talk msg error : %s", sendMsgResponse.getErrmsg())); |
||||||
|
logger.info("alert send ding talk msg error : {}", sendMsgResponse.getErrmsg()); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkAlertChannelFactoryTest |
||||||
|
*/ |
||||||
|
public class DingTalkAlertChannelFactoryTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testGetParams() { |
||||||
|
DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new DingTalkAlertChannelFactory(); |
||||||
|
List<PluginParams> params = dingTalkAlertChannelFactory.getParams(); |
||||||
|
JSONUtils.toJsonString(params); |
||||||
|
Assert.assertEquals(7, params.size()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCreate() { |
||||||
|
DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new DingTalkAlertChannelFactory(); |
||||||
|
AlertChannel alertChannel = dingTalkAlertChannelFactory.create(); |
||||||
|
Assert.assertNotNull(alertChannel); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.dingtalk; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* DingTalkSenderTest |
||||||
|
*/ |
||||||
|
public class DingTalkSenderTest { |
||||||
|
|
||||||
|
private static Map<String, String> dingTalkConfig = new HashMap<>(); |
||||||
|
|
||||||
|
@Before |
||||||
|
public void initDingTalkConfig() { |
||||||
|
|
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, "keyWord"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, "url"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, "false"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, "password"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PORT, "9988"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_USER, "user1,user2"); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSend() { |
||||||
|
DingTalkSender dingTalkSender = new DingTalkSender(dingTalkConfig); |
||||||
|
dingTalkSender.sendDingTalkMsg("keyWord+Welcome", "UTF-8"); |
||||||
|
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, "true"); |
||||||
|
dingTalkSender = new DingTalkSender(dingTalkConfig); |
||||||
|
AlertResult alertResult = dingTalkSender.sendDingTalkMsg("keyWord+Welcome", "UTF-8"); |
||||||
|
Assert.assertEquals("false",alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,128 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-alert-email</artifactId> |
||||||
|
<!-- can be load as a Alert Plugin when development and run server in IDE --> |
||||||
|
<packaging>dolphinscheduler-plugin</packaging> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-spi</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-annotations</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-databind</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.commons</groupId> |
||||||
|
<artifactId>commons-collections4</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.poi</groupId> |
||||||
|
<artifactId>poi</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>slf4j-api</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.commons</groupId> |
||||||
|
<artifactId>commons-email</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-annotations</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-databind</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<type>jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.powermock</groupId> |
||||||
|
<artifactId>powermock-module-junit4</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.powermock</groupId> |
||||||
|
<artifactId>powermock-api-mockito2</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
<exclusions> |
||||||
|
<exclusion> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
</exclusion> |
||||||
|
</exclusions> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>dolphinscheduler-alert-email-${project.version}</finalName> |
||||||
|
</build> |
||||||
|
|
||||||
|
</project> |
@ -0,0 +1,69 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* email alert channel . use email to seed the alertInfo |
||||||
|
*/ |
||||||
|
public class EmailAlertChannel implements AlertChannel { |
||||||
|
private static final Logger logger = LoggerFactory.getLogger(EmailAlertChannel.class); |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertResult process(AlertInfo info) { |
||||||
|
|
||||||
|
AlertData alert = info.getAlertData(); |
||||||
|
String alertParams = info.getAlertParams(); |
||||||
|
Map<String, String> paramsMap = PluginParamsTransfer.getPluginParamsMap(alertParams); |
||||||
|
MailSender mailSender = new MailSender(paramsMap); |
||||||
|
AlertResult alertResult = mailSender.sendMails(alert.getTitle(), alert.getContent()); |
||||||
|
|
||||||
|
//send flag
|
||||||
|
boolean flag = false; |
||||||
|
|
||||||
|
if (alertResult == null) { |
||||||
|
alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
alertResult.setMessage("alert send error."); |
||||||
|
logger.info("alert send error : {}", alertResult.getMessage()); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
flag = Boolean.parseBoolean(String.valueOf(alertResult.getStatus())); |
||||||
|
|
||||||
|
if (flag) { |
||||||
|
logger.info("alert send success"); |
||||||
|
alertResult.setMessage("email send success."); |
||||||
|
} else { |
||||||
|
alertResult.setMessage("alert send error."); |
||||||
|
logger.info("alert send error : {}", alertResult.getMessage()); |
||||||
|
} |
||||||
|
|
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,137 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PasswordParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.RadioParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.DataType; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* email alert factory |
||||||
|
*/ |
||||||
|
public class EmailAlertChannelFactory implements AlertChannelFactory { |
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "Email"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<PluginParams> getParams() { |
||||||
|
|
||||||
|
List<PluginParams> paramsList = new ArrayList<>(); |
||||||
|
InputParam receivesParam = InputParam.newBuilder(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERS, MailParamsConstants.PLUGIN_DEFAULT_EMAIL_RECEIVERS) |
||||||
|
.setPlaceholder("please input receives") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam receiveCcsParam = InputParam.newBuilder(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERCCS, MailParamsConstants.PLUGIN_DEFAULT_EMAIL_RECEIVERCCS) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSmtpHost = InputParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_HOST, MailParamsConstants.MAIL_SMTP_HOST) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSmtpPort = InputParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_PORT, MailParamsConstants.MAIL_SMTP_PORT) |
||||||
|
.setValue(25) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.setType(DataType.NUMBER.getDataType()) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSender = InputParam.newBuilder(MailParamsConstants.NAME_MAIL_SENDER, MailParamsConstants.MAIL_SENDER) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableSmtpAuth = RadioParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_AUTH, MailParamsConstants.MAIL_SMTP_AUTH) |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.setValue(true) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailUser = InputParam.newBuilder(MailParamsConstants.NAME_MAIL_USER, MailParamsConstants.MAIL_USER) |
||||||
|
.setPlaceholder("if enable use authentication, you need input user") |
||||||
|
.build(); |
||||||
|
|
||||||
|
PasswordParam mailPassword = PasswordParam.newBuilder(MailParamsConstants.NAME_MAIL_PASSWD, MailParamsConstants.MAIL_PASSWD) |
||||||
|
.setPlaceholder("if enable use authentication, you need input password") |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableTls = RadioParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_STARTTLS_ENABLE, MailParamsConstants.MAIL_SMTP_STARTTLS_ENABLE) |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.setValue(false) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableSsl = RadioParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_SSL_ENABLE, MailParamsConstants.MAIL_SMTP_SSL_ENABLE) |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.setValue(false) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam sslTrust = InputParam.newBuilder(MailParamsConstants.NAME_MAIL_SMTP_SSL_TRUST, MailParamsConstants.MAIL_SMTP_SSL_TRUST) |
||||||
|
.setValue("*") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam showType = RadioParam.newBuilder(AlertConstants.SHOW_TYPE, AlertConstants.SHOW_TYPE) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.TABLE.getDescp(), ShowType.TABLE.getDescp(), false)) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.TEXT.getDescp(), ShowType.TEXT.getDescp(), false)) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.ATTACHMENT.getDescp(), ShowType.ATTACHMENT.getDescp(), false)) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.TABLEATTACHMENT.getDescp(), ShowType.TABLEATTACHMENT.getDescp(), false)) |
||||||
|
.setValue(ShowType.TABLE.getDescp()) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
paramsList.add(receivesParam); |
||||||
|
paramsList.add(receiveCcsParam); |
||||||
|
paramsList.add(mailSmtpHost); |
||||||
|
paramsList.add(mailSmtpPort); |
||||||
|
paramsList.add(mailSender); |
||||||
|
paramsList.add(enableSmtpAuth); |
||||||
|
paramsList.add(mailUser); |
||||||
|
paramsList.add(mailPassword); |
||||||
|
paramsList.add(enableTls); |
||||||
|
paramsList.add(enableSsl); |
||||||
|
paramsList.add(sslTrust); |
||||||
|
paramsList.add(showType); |
||||||
|
|
||||||
|
return paramsList; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertChannel create() { |
||||||
|
return new EmailAlertChannel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* email alert plugin |
||||||
|
*/ |
||||||
|
public class EmailAlertPlugin implements DolphinSchedulerPlugin { |
||||||
|
@Override |
||||||
|
public Iterable<AlertChannelFactory> getAlertChannelFactorys() { |
||||||
|
return ImmutableList.of(new EmailAlertChannelFactory()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
public class EmailConstants { |
||||||
|
|
||||||
|
|
||||||
|
public static final String XLS_FILE_PATH = "xls.file.path"; |
||||||
|
|
||||||
|
public static final String MAIL_TRANSPORT_PROTOCOL = "mail.transport.protocol"; |
||||||
|
|
||||||
|
public static final String DEFAULT_SMTP_PORT = "25"; |
||||||
|
|
||||||
|
public static final String TEXT_HTML_CHARSET_UTF_8 = "text/html;charset=utf-8"; |
||||||
|
|
||||||
|
public static final int NUMBER_1000 = 1000; |
||||||
|
|
||||||
|
public static final String TR = "<tr>"; |
||||||
|
|
||||||
|
public static final String TD = "<td>"; |
||||||
|
|
||||||
|
public static final String TD_END = "</td>"; |
||||||
|
|
||||||
|
public static final String TR_END = "</tr>"; |
||||||
|
|
||||||
|
public static final String TITLE = "title"; |
||||||
|
|
||||||
|
public static final String CONTENT = "content"; |
||||||
|
|
||||||
|
public static final String TH = "<th>"; |
||||||
|
|
||||||
|
public static final String TH_END = "</th>"; |
||||||
|
|
||||||
|
public static final String MARKDOWN_QUOTE = ">"; |
||||||
|
|
||||||
|
public static final String MARKDOWN_ENTER = "\n"; |
||||||
|
|
||||||
|
public static final String HTML_HEADER_PREFIX = new StringBuilder("<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>") |
||||||
|
.append("<html>") |
||||||
|
.append("<head>") |
||||||
|
.append("<title>dolphinscheduler</title>") |
||||||
|
.append("<meta name='Keywords' content=''>") |
||||||
|
.append("<meta name='Description' content=''>") |
||||||
|
.append("<style type=\"text/css\">") |
||||||
|
.append("table {margin-top:0px;padding-top:0px;border:1px solid;font-size: 14px;color: #333333;border-width: 1px;border-color: #666666;border-collapse: collapse;}") |
||||||
|
.append("table th {border-width: 1px;padding: 8px;border-style: solid;border-color: #666666;background-color: #dedede;text-align: left;}") |
||||||
|
.append("table td {border-width: 1px;padding: 8px;border-style: solid;border-color: #666666;background-color: #ffffff;text-align: left;}") |
||||||
|
.append("</style>") |
||||||
|
.append("</head>") |
||||||
|
.append("<body style=\"margin:0;padding:0\"><table border=\"1px\" cellpadding=\"5px\" cellspacing=\"-10px\"> ") |
||||||
|
.toString(); |
||||||
|
|
||||||
|
public static final String TABLE_BODY_HTML_TAIL = "</table></body></html>"; |
||||||
|
|
||||||
|
public static final String UTF_8 = "UTF-8"; |
||||||
|
|
||||||
|
public static final String EXCEL_SUFFIX_XLS = ".xls"; |
||||||
|
|
||||||
|
public static final String SINGLE_SLASH = "/"; |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
/** |
||||||
|
* mail plugin params json use |
||||||
|
*/ |
||||||
|
public class MailParamsConstants { |
||||||
|
|
||||||
|
public MailParamsConstants() { |
||||||
|
throw new IllegalStateException("Utility class"); |
||||||
|
} |
||||||
|
|
||||||
|
public static final String PLUGIN_DEFAULT_EMAIL_RECEIVERS = "$t('receivers')"; |
||||||
|
public static final String NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERS = "receivers"; |
||||||
|
|
||||||
|
public static final String PLUGIN_DEFAULT_EMAIL_RECEIVERCCS = "$t('receiverCcs')"; |
||||||
|
public static final String NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERCCS = "receiverCcs"; |
||||||
|
|
||||||
|
public static final String MAIL_PROTOCOL = "transport.protocol"; |
||||||
|
public static final String NAME_MAIL_PROTOCOL = "protocol"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_HOST = "smtp.host"; |
||||||
|
public static final String NAME_MAIL_SMTP_HOST = "serverHost"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_PORT = "smtp.port"; |
||||||
|
public static final String NAME_MAIL_SMTP_PORT = "serverPort"; |
||||||
|
|
||||||
|
public static final String MAIL_SENDER = "sender"; |
||||||
|
public static final String NAME_MAIL_SENDER = "sender"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_AUTH = "smtp.auth"; |
||||||
|
public static final String NAME_MAIL_SMTP_AUTH = "enableSmtpAuth"; |
||||||
|
|
||||||
|
public static final String MAIL_USER = "user"; |
||||||
|
public static final String NAME_MAIL_USER = "user"; |
||||||
|
|
||||||
|
public static final String MAIL_PASSWD = "passwd"; |
||||||
|
public static final String NAME_MAIL_PASSWD = "passwd"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_STARTTLS_ENABLE = "smtp.starttls.enable"; |
||||||
|
public static final String NAME_MAIL_SMTP_STARTTLS_ENABLE = "starttlsEnable"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_SSL_ENABLE = "smtp.ssl.enable"; |
||||||
|
public static final String NAME_MAIL_SMTP_SSL_ENABLE = "sslEnable"; |
||||||
|
|
||||||
|
public static final String MAIL_SMTP_SSL_TRUST = "smtp.ssl.trust"; |
||||||
|
public static final String NAME_MAIL_SMTP_SSL_TRUST = "smtpSslTrust"; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,429 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.plugin.alert.email.template.AlertTemplate; |
||||||
|
import org.apache.dolphinscheduler.plugin.alert.email.template.DefaultHTMLTemplate; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils; |
||||||
|
import org.apache.commons.mail.EmailException; |
||||||
|
import org.apache.commons.mail.HtmlEmail; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Properties; |
||||||
|
|
||||||
|
import javax.mail.Authenticator; |
||||||
|
import javax.mail.Message; |
||||||
|
import javax.mail.MessagingException; |
||||||
|
import javax.mail.PasswordAuthentication; |
||||||
|
import javax.mail.Session; |
||||||
|
import javax.mail.Transport; |
||||||
|
import javax.mail.internet.InternetAddress; |
||||||
|
import javax.mail.internet.MimeBodyPart; |
||||||
|
import javax.mail.internet.MimeMessage; |
||||||
|
import javax.mail.internet.MimeMultipart; |
||||||
|
import javax.mail.internet.MimeUtility; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import com.sun.mail.smtp.SMTPProvider; |
||||||
|
|
||||||
|
/** |
||||||
|
* mail utils |
||||||
|
*/ |
||||||
|
public class MailSender { |
||||||
|
|
||||||
|
public static final Logger logger = LoggerFactory.getLogger(MailSender.class); |
||||||
|
|
||||||
|
private List<String> receivers; |
||||||
|
private List<String> receiverCcs; |
||||||
|
private String mailProtocol = "SMTP"; |
||||||
|
private String mailSmtpHost; |
||||||
|
private String mailSmtpPort; |
||||||
|
private String mailSender; |
||||||
|
private String enableSmtpAuth; |
||||||
|
private String mailUser; |
||||||
|
private String mailPasswd; |
||||||
|
private String mailUseStartTLS; |
||||||
|
private String mailUseSSL; |
||||||
|
private String xlsFilePath; |
||||||
|
private String sslTrust; |
||||||
|
private String showType; |
||||||
|
private AlertTemplate alertTemplate; |
||||||
|
|
||||||
|
public MailSender(Map<String, String> config) { |
||||||
|
|
||||||
|
String receiversConfig = config.get(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERS); |
||||||
|
if (receiversConfig == null || "".equals(receiversConfig)) { |
||||||
|
throw new RuntimeException(MailParamsConstants.PLUGIN_DEFAULT_EMAIL_RECEIVERS + "must not be null"); |
||||||
|
} |
||||||
|
|
||||||
|
receivers = Arrays.asList(receiversConfig.split(",")); |
||||||
|
|
||||||
|
String receiverCcsConfig = config.get(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERCCS); |
||||||
|
|
||||||
|
receiverCcs = new ArrayList<>(); |
||||||
|
if (receiverCcsConfig != null && !"".equals(receiverCcsConfig)) { |
||||||
|
receiverCcs = Arrays.asList(receiverCcsConfig.split(",")); |
||||||
|
} |
||||||
|
|
||||||
|
mailSmtpHost = config.get(MailParamsConstants.NAME_MAIL_SMTP_HOST); |
||||||
|
requireNonNull(mailSmtpHost, MailParamsConstants.MAIL_SMTP_HOST + " must not null"); |
||||||
|
|
||||||
|
mailSmtpPort = config.get(MailParamsConstants.NAME_MAIL_SMTP_PORT); |
||||||
|
requireNonNull(mailSmtpPort, MailParamsConstants.MAIL_SMTP_PORT + " must not null"); |
||||||
|
|
||||||
|
mailSender = config.get(MailParamsConstants.NAME_MAIL_SENDER); |
||||||
|
requireNonNull(mailSender, MailParamsConstants.MAIL_SENDER + " must not null"); |
||||||
|
|
||||||
|
enableSmtpAuth = config.get(MailParamsConstants.NAME_MAIL_SMTP_AUTH); |
||||||
|
|
||||||
|
mailUser = config.get(MailParamsConstants.NAME_MAIL_USER); |
||||||
|
requireNonNull(mailUser, MailParamsConstants.MAIL_USER + " must not null"); |
||||||
|
|
||||||
|
mailPasswd = config.get(MailParamsConstants.NAME_MAIL_PASSWD); |
||||||
|
requireNonNull(mailPasswd, MailParamsConstants.MAIL_PASSWD + " must not null"); |
||||||
|
|
||||||
|
mailUseStartTLS = config.get(MailParamsConstants.NAME_MAIL_SMTP_STARTTLS_ENABLE); |
||||||
|
requireNonNull(mailUseStartTLS, MailParamsConstants.MAIL_SMTP_STARTTLS_ENABLE + " must not null"); |
||||||
|
|
||||||
|
mailUseSSL = config.get(MailParamsConstants.NAME_MAIL_SMTP_SSL_ENABLE); |
||||||
|
requireNonNull(mailUseSSL, MailParamsConstants.MAIL_SMTP_SSL_ENABLE + " must not null"); |
||||||
|
|
||||||
|
sslTrust = config.get(MailParamsConstants.NAME_MAIL_SMTP_SSL_TRUST); |
||||||
|
requireNonNull(sslTrust, MailParamsConstants.MAIL_SMTP_SSL_TRUST + " must not null"); |
||||||
|
|
||||||
|
showType = config.get(AlertConstants.SHOW_TYPE); |
||||||
|
requireNonNull(showType, AlertConstants.SHOW_TYPE + " must not null"); |
||||||
|
|
||||||
|
xlsFilePath = config.get(EmailConstants.XLS_FILE_PATH); |
||||||
|
if (StringUtils.isBlank(xlsFilePath)) { |
||||||
|
xlsFilePath = "/tmp/xls"; |
||||||
|
} |
||||||
|
|
||||||
|
alertTemplate = new DefaultHTMLTemplate(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send mail to receivers |
||||||
|
* |
||||||
|
* @param title title |
||||||
|
* @param content content |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public AlertResult sendMails(String title, String content) { |
||||||
|
return sendMails(this.receivers, this.receiverCcs, title, content); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send mail to receivers |
||||||
|
* |
||||||
|
* @param title email title |
||||||
|
* @param content email content |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public AlertResult sendMailsToReceiverOnly(String title, String content) { |
||||||
|
return sendMails(this.receivers, null, title, content); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send mail |
||||||
|
* |
||||||
|
* @param receivers receivers |
||||||
|
* @param receiverCcs receiverCcs |
||||||
|
* @param title title |
||||||
|
* @param content content |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public AlertResult sendMails(List<String> receivers, List<String> receiverCcs, String title, String content) { |
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
|
||||||
|
// if there is no receivers && no receiversCc, no need to process
|
||||||
|
if (CollectionUtils.isEmpty(receivers) && CollectionUtils.isEmpty(receiverCcs)) { |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
receivers.removeIf(StringUtils::isEmpty); |
||||||
|
|
||||||
|
if (showType.equals(ShowType.TABLE.getDescp()) || showType.equals(ShowType.TEXT.getDescp())) { |
||||||
|
// send email
|
||||||
|
HtmlEmail email = new HtmlEmail(); |
||||||
|
|
||||||
|
try { |
||||||
|
Session session = getSession(); |
||||||
|
email.setMailSession(session); |
||||||
|
email.setFrom(mailSender); |
||||||
|
email.setCharset(EmailConstants.UTF_8); |
||||||
|
if (CollectionUtils.isNotEmpty(receivers)) { |
||||||
|
// receivers mail
|
||||||
|
for (String receiver : receivers) { |
||||||
|
email.addTo(receiver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(receiverCcs)) { |
||||||
|
//cc
|
||||||
|
for (String receiverCc : receiverCcs) { |
||||||
|
email.addCc(receiverCc); |
||||||
|
} |
||||||
|
} |
||||||
|
// sender mail
|
||||||
|
return getStringObjectMap(title, content, alertResult, email); |
||||||
|
} catch (Exception e) { |
||||||
|
handleException(alertResult, e); |
||||||
|
} |
||||||
|
} else if (showType.equals(ShowType.ATTACHMENT.getDescp()) || showType.equals(ShowType.TABLEATTACHMENT.getDescp())) { |
||||||
|
try { |
||||||
|
|
||||||
|
String partContent = (showType.equals(ShowType.ATTACHMENT.getDescp()) ? "Please see the attachment " + title + EmailConstants.EXCEL_SUFFIX_XLS : htmlTable(content, false)); |
||||||
|
|
||||||
|
attachment(title, content, partContent); |
||||||
|
|
||||||
|
alertResult.setStatus("true"); |
||||||
|
return alertResult; |
||||||
|
} catch (Exception e) { |
||||||
|
handleException(alertResult, e); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
} |
||||||
|
return alertResult; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* html table content |
||||||
|
* |
||||||
|
* @param content the content |
||||||
|
* @param showAll if show the whole content |
||||||
|
* @return the html table form |
||||||
|
*/ |
||||||
|
private String htmlTable(String content, boolean showAll) { |
||||||
|
return alertTemplate.getMessageFromTemplate(content, ShowType.TABLE, showAll); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* html table content |
||||||
|
* |
||||||
|
* @param content the content |
||||||
|
* @return the html table form |
||||||
|
*/ |
||||||
|
private String htmlTable(String content) { |
||||||
|
return htmlTable(content, true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* html text content |
||||||
|
* |
||||||
|
* @param content the content |
||||||
|
* @return text in html form |
||||||
|
*/ |
||||||
|
private String htmlText(String content) { |
||||||
|
return alertTemplate.getMessageFromTemplate(content, ShowType.TEXT); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send mail as Excel attachment |
||||||
|
* |
||||||
|
* @param title |
||||||
|
* @param content |
||||||
|
* @param partContent |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
private void attachment(String title, String content, String partContent) throws Exception { |
||||||
|
MimeMessage msg = getMimeMessage(); |
||||||
|
|
||||||
|
attachContent(title, content, partContent, msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get MimeMessage |
||||||
|
* |
||||||
|
* @return |
||||||
|
* @throws MessagingException |
||||||
|
*/ |
||||||
|
private MimeMessage getMimeMessage() throws MessagingException { |
||||||
|
|
||||||
|
// 1. The first step in creating mail: creating session
|
||||||
|
Session session = getSession(); |
||||||
|
// Setting debug mode, can be turned off
|
||||||
|
session.setDebug(false); |
||||||
|
|
||||||
|
// 2. creating mail: Creating a MimeMessage
|
||||||
|
MimeMessage msg = new MimeMessage(session); |
||||||
|
// 3. set sender
|
||||||
|
msg.setFrom(new InternetAddress(mailSender)); |
||||||
|
// 4. set receivers
|
||||||
|
for (String receiver : receivers) { |
||||||
|
msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver)); |
||||||
|
} |
||||||
|
return msg; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get session |
||||||
|
* |
||||||
|
* @return the new Session |
||||||
|
*/ |
||||||
|
private Session getSession() { |
||||||
|
Properties props = new Properties(); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_HOST, mailSmtpHost); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_PORT, mailSmtpPort); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_AUTH, enableSmtpAuth); |
||||||
|
props.setProperty(EmailConstants.MAIL_TRANSPORT_PROTOCOL, mailProtocol); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_STARTTLS_ENABLE, mailUseStartTLS); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_SSL_ENABLE, mailUseSSL); |
||||||
|
props.setProperty(MailParamsConstants.MAIL_SMTP_SSL_TRUST, sslTrust); |
||||||
|
|
||||||
|
Authenticator auth = new Authenticator() { |
||||||
|
@Override |
||||||
|
protected PasswordAuthentication getPasswordAuthentication() { |
||||||
|
// mail username and password
|
||||||
|
return new PasswordAuthentication(mailUser, mailPasswd); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Session session = Session.getInstance(props, auth); |
||||||
|
session.addProvider(new SMTPProvider()); |
||||||
|
return session; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* attach content |
||||||
|
* |
||||||
|
* @param title |
||||||
|
* @param content |
||||||
|
* @param partContent |
||||||
|
* @param msg |
||||||
|
* @throws MessagingException |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
private void attachContent(String title, String content, String partContent, MimeMessage msg) throws MessagingException, IOException { |
||||||
|
/** |
||||||
|
* set receiverCc |
||||||
|
*/ |
||||||
|
if (CollectionUtils.isNotEmpty(receiverCcs)) { |
||||||
|
for (String receiverCc : receiverCcs) { |
||||||
|
msg.addRecipients(Message.RecipientType.CC, InternetAddress.parse(receiverCc)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// set subject
|
||||||
|
msg.setSubject(title); |
||||||
|
MimeMultipart partList = new MimeMultipart(); |
||||||
|
// set signature
|
||||||
|
MimeBodyPart part1 = new MimeBodyPart(); |
||||||
|
part1.setContent(partContent, EmailConstants.TEXT_HTML_CHARSET_UTF_8); |
||||||
|
// set attach file
|
||||||
|
MimeBodyPart part2 = new MimeBodyPart(); |
||||||
|
File file = new File(xlsFilePath + EmailConstants.SINGLE_SLASH + title + EmailConstants.EXCEL_SUFFIX_XLS); |
||||||
|
if (!file.getParentFile().exists()) { |
||||||
|
file.getParentFile().mkdirs(); |
||||||
|
} |
||||||
|
// make excel file
|
||||||
|
|
||||||
|
ExcelUtils.genExcelFile(content, title, xlsFilePath); |
||||||
|
|
||||||
|
part2.attachFile(file); |
||||||
|
part2.setFileName(MimeUtility.encodeText(title + EmailConstants.EXCEL_SUFFIX_XLS, EmailConstants.UTF_8, "B")); |
||||||
|
// add components to collection
|
||||||
|
partList.addBodyPart(part1); |
||||||
|
partList.addBodyPart(part2); |
||||||
|
msg.setContent(partList); |
||||||
|
// 5. send Transport
|
||||||
|
Transport.send(msg); |
||||||
|
// 6. delete saved file
|
||||||
|
deleteFile(file); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* the string object map |
||||||
|
* |
||||||
|
* @param title |
||||||
|
* @param content |
||||||
|
* @param alertResult |
||||||
|
* @param email |
||||||
|
* @return |
||||||
|
* @throws EmailException |
||||||
|
*/ |
||||||
|
private AlertResult getStringObjectMap(String title, String content, AlertResult alertResult, HtmlEmail email) throws EmailException { |
||||||
|
|
||||||
|
/** |
||||||
|
* the subject of the message to be sent |
||||||
|
*/ |
||||||
|
email.setSubject(title); |
||||||
|
/** |
||||||
|
* to send information, you can use HTML tags in mail content because of the use of HtmlEmail |
||||||
|
*/ |
||||||
|
if (showType.equals(ShowType.TABLE.getDescp())) { |
||||||
|
email.setMsg(htmlTable(content)); |
||||||
|
} else if (showType.equals(ShowType.TEXT.getDescp())) { |
||||||
|
email.setMsg(htmlText(content)); |
||||||
|
} |
||||||
|
|
||||||
|
// send
|
||||||
|
email.setDebug(true); |
||||||
|
Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); |
||||||
|
email.send(); |
||||||
|
|
||||||
|
alertResult.setStatus("true"); |
||||||
|
|
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* file delete |
||||||
|
* |
||||||
|
* @param file the file to delete |
||||||
|
*/ |
||||||
|
public void deleteFile(File file) { |
||||||
|
if (file.exists()) { |
||||||
|
if (file.delete()) { |
||||||
|
logger.info("delete success: {}", file.getAbsolutePath() + file.getName()); |
||||||
|
} else { |
||||||
|
logger.info("delete fail: {}", file.getAbsolutePath() + file.getName()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
logger.info("file not exists: {}", file.getAbsolutePath() + file.getName()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* handle exception |
||||||
|
* |
||||||
|
* @param alertResult |
||||||
|
* @param e |
||||||
|
*/ |
||||||
|
private void handleException(AlertResult alertResult, Exception e) { |
||||||
|
logger.error("Send email to {} failed", receivers, e); |
||||||
|
alertResult.setMessage("Send email to {" + String.join(",", receivers) + "} failed," + e.toString()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* EmailAlertChannelFactory Tester. |
||||||
|
* |
||||||
|
* @version 1.0 |
||||||
|
* @since <pre>Aug 20, 2020</pre> |
||||||
|
*/ |
||||||
|
public class EmailAlertChannelFactoryTest { |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() throws Exception { |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void after() throws Exception { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: getName() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetName() throws Exception { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: getParams() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetParams() throws Exception { |
||||||
|
EmailAlertChannelFactory emailAlertChannelFactory = new EmailAlertChannelFactory(); |
||||||
|
List<PluginParams> params = emailAlertChannelFactory.getParams(); |
||||||
|
System.out.println(JSONUtils.toJsonString(params)); |
||||||
|
Assert.assertEquals(12, params.size()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: create() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testCreate() throws Exception { |
||||||
|
EmailAlertChannelFactory emailAlertChannelFactory = new EmailAlertChannelFactory(); |
||||||
|
AlertChannel alertChannel = emailAlertChannelFactory.create(); |
||||||
|
Assert.assertNotNull(alertChannel); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,161 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PasswordParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.RadioParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.DataType; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* EmailAlertChannel Tester. |
||||||
|
*/ |
||||||
|
public class EmailAlertChannelTest { |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: process(AlertInfo info) |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testProcess() { |
||||||
|
EmailAlertChannel emailAlertChannel = new EmailAlertChannel(); |
||||||
|
AlertData alertData = new AlertData(); |
||||||
|
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
||||||
|
map1.put("mysql service name", "mysql200"); |
||||||
|
map1.put("mysql address", "192.168.xx.xx"); |
||||||
|
map1.put("port", "3306"); |
||||||
|
map1.put("no index of number", "80"); |
||||||
|
map1.put("database client connections", "190"); |
||||||
|
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
||||||
|
maps.add(0, map1); |
||||||
|
String mapjson = JSONUtils.toJsonString(maps); |
||||||
|
|
||||||
|
alertData.setId(10) |
||||||
|
.setContent(mapjson) |
||||||
|
.setLog("10") |
||||||
|
.setTitle("test"); |
||||||
|
AlertInfo alertInfo = new AlertInfo(); |
||||||
|
alertInfo.setAlertData(alertData); |
||||||
|
alertInfo.setAlertParams(getEmailAlertParams()); |
||||||
|
AlertResult alertResult = emailAlertChannel.process(alertInfo); |
||||||
|
Assert.assertNotNull(alertResult); |
||||||
|
Assert.assertEquals("false", alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
public String getEmailAlertParams() { |
||||||
|
List<PluginParams> paramsList = new ArrayList<>(); |
||||||
|
InputParam receivesParam = InputParam.newBuilder("receivers", "receivers") |
||||||
|
.setValue("540957506@qq.com") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSmtpHost = InputParam.newBuilder("serverHost", "smtp.host") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue("smtp.126.com") |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSmtpPort = InputParam.newBuilder("serverPort", "smtp.port") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.setType(DataType.NUMBER.getDataType()) |
||||||
|
.build()) |
||||||
|
.setValue(25) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailSender = InputParam.newBuilder("sender", "sender") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue("dolphinscheduler@126.com") |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableSmtpAuth = RadioParam.newBuilder("enableSmtpAuth", "smtp.auth") |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue(false) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam mailUser = InputParam.newBuilder("user", "user") |
||||||
|
.setPlaceholder("if enable use authentication, you need input user") |
||||||
|
.setValue("dolphinscheduler@126.com") |
||||||
|
.build(); |
||||||
|
|
||||||
|
PasswordParam mailPassword = PasswordParam.newBuilder("passwd", "passwd") |
||||||
|
.setPlaceholder("if enable use authentication, you need input password") |
||||||
|
.setValue("escheduler123") |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableTls = RadioParam.newBuilder("starttlsEnable", "starttls.enable") |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue(true) |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam enableSsl = RadioParam.newBuilder("sslEnable", "smtp.ssl.enable") |
||||||
|
.addParamsOptions(new ParamsOptions("YES", true, false)) |
||||||
|
.addParamsOptions(new ParamsOptions("NO", false, false)) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue(true) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam sslTrust = InputParam.newBuilder("smtpSslTrust", "smtp.ssl.trust") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue("smtp.126.com") |
||||||
|
.build(); |
||||||
|
|
||||||
|
List<ParamsOptions> emailShowTypeList = new ArrayList<>(); |
||||||
|
emailShowTypeList.add(new ParamsOptions(ShowType.TABLE.getDescp(), ShowType.TABLE.getDescp(), false)); |
||||||
|
emailShowTypeList.add(new ParamsOptions(ShowType.TEXT.getDescp(), ShowType.TEXT.getDescp(), false)); |
||||||
|
emailShowTypeList.add(new ParamsOptions(ShowType.ATTACHMENT.getDescp(), ShowType.ATTACHMENT.getDescp(), false)); |
||||||
|
emailShowTypeList.add(new ParamsOptions(ShowType.TABLEATTACHMENT.getDescp(), ShowType.TABLEATTACHMENT.getDescp(), false)); |
||||||
|
RadioParam showType = RadioParam.newBuilder(AlertConstants.SHOW_TYPE, "showType") |
||||||
|
.setParamsOptionsList(emailShowTypeList) |
||||||
|
.setValue(ShowType.TABLE.getDescp()) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
paramsList.add(receivesParam); |
||||||
|
paramsList.add(mailSmtpHost); |
||||||
|
paramsList.add(mailSmtpPort); |
||||||
|
paramsList.add(mailSender); |
||||||
|
paramsList.add(enableSmtpAuth); |
||||||
|
paramsList.add(mailUser); |
||||||
|
paramsList.add(mailPassword); |
||||||
|
paramsList.add(enableTls); |
||||||
|
paramsList.add(enableSsl); |
||||||
|
paramsList.add(sslTrust); |
||||||
|
paramsList.add(showType); |
||||||
|
|
||||||
|
return JSONUtils.toJsonString(paramsList); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,136 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.plugin.alert.email.template.AlertTemplate; |
||||||
|
import org.apache.dolphinscheduler.plugin.alert.email.template.DefaultHTMLTemplate; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.BeforeClass; |
||||||
|
import org.junit.Test; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
*/ |
||||||
|
public class MailUtilsTest { |
||||||
|
private static final Logger logger = LoggerFactory.getLogger(MailUtilsTest.class); |
||||||
|
|
||||||
|
private static Map<String, String> emailConfig = new HashMap<>(); |
||||||
|
|
||||||
|
private static AlertTemplate alertTemplate; |
||||||
|
|
||||||
|
static MailSender mailSender; |
||||||
|
|
||||||
|
@BeforeClass |
||||||
|
public static void initEmailConfig() { |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_PROTOCOL, "smtp"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SMTP_HOST, "xxx.xxx.com"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SMTP_PORT, "25"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SENDER, "xxx1.xxx.com"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_USER, "xxx2.xxx.com"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_PASSWD, "111111"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SMTP_STARTTLS_ENABLE, "true"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SMTP_SSL_ENABLE, "false"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_MAIL_SMTP_SSL_TRUST, "false"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERS, "347801120@qq.com"); |
||||||
|
emailConfig.put(MailParamsConstants.NAME_PLUGIN_DEFAULT_EMAIL_RECEIVERCCS, "347801120@qq.com"); |
||||||
|
emailConfig.put(AlertConstants.SHOW_TYPE, ShowType.TEXT.getDescp()); |
||||||
|
alertTemplate = new DefaultHTMLTemplate(); |
||||||
|
mailSender = new MailSender(emailConfig); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendMails() { |
||||||
|
|
||||||
|
String content = "[\"id:69\"," |
||||||
|
+ "\"name:UserBehavior-0--1193959466\"," |
||||||
|
+ "\"Job name: Start workflow\"," |
||||||
|
+ "\"State: SUCCESS\"," |
||||||
|
+ "\"Recovery:NO\"," |
||||||
|
+ "\"Run time: 1\"," |
||||||
|
+ "\"Start time: 2018-08-06 10:31:34.0\"," |
||||||
|
+ "\"End time: 2018-08-06 10:31:49.0\"," |
||||||
|
+ "\"Host: 192.168.xx.xx\"," |
||||||
|
+ "\"Notify group :4\"]"; |
||||||
|
|
||||||
|
mailSender.sendMails( |
||||||
|
"Mysql Exception", |
||||||
|
content); |
||||||
|
} |
||||||
|
|
||||||
|
public String list2String() { |
||||||
|
|
||||||
|
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
||||||
|
map1.put("mysql service name", "mysql200"); |
||||||
|
map1.put("mysql address", "192.168.xx.xx"); |
||||||
|
map1.put("port", "3306"); |
||||||
|
map1.put("no index of number", "80"); |
||||||
|
map1.put("database client connections", "190"); |
||||||
|
|
||||||
|
LinkedHashMap<String, Object> map2 = new LinkedHashMap<>(); |
||||||
|
map2.put("mysql service name", "mysql210"); |
||||||
|
map2.put("mysql address", "192.168.xx.xx"); |
||||||
|
map2.put("port", "3306"); |
||||||
|
map2.put("no index of number", "10"); |
||||||
|
map2.put("database client connections", "90"); |
||||||
|
|
||||||
|
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
||||||
|
maps.add(0, map1); |
||||||
|
maps.add(1, map2); |
||||||
|
String mapjson = JSONUtils.toJsonString(maps); |
||||||
|
logger.info(mapjson); |
||||||
|
|
||||||
|
return mapjson; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendTableMail() { |
||||||
|
String title = "Mysql Exception"; |
||||||
|
String content = list2String(); |
||||||
|
emailConfig.put(AlertConstants.SHOW_TYPE, ShowType.TABLE.getDescp()); |
||||||
|
mailSender = new MailSender(emailConfig); |
||||||
|
mailSender.sendMails(title, content); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testAttachmentFile() throws Exception { |
||||||
|
String content = list2String(); |
||||||
|
emailConfig.put(AlertConstants.SHOW_TYPE, ShowType.ATTACHMENT.getDescp()); |
||||||
|
mailSender = new MailSender(emailConfig); |
||||||
|
mailSender.sendMails("gaojing", content); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testTableAttachmentFile() throws Exception { |
||||||
|
String content = list2String(); |
||||||
|
emailConfig.put(AlertConstants.SHOW_TYPE, ShowType.TABLEATTACHMENT.getDescp()); |
||||||
|
mailSender = new MailSender(emailConfig); |
||||||
|
mailSender.sendMails("gaojing", content); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,105 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.email.template; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.plugin.alert.email.EmailConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* test class for DefaultHTMLTemplate |
||||||
|
*/ |
||||||
|
public class DefaultHTMLTemplateTest { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DefaultHTMLTemplateTest.class); |
||||||
|
|
||||||
|
/** |
||||||
|
* only need test method GetMessageFromTemplate |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testGetMessageFromTemplate() { |
||||||
|
|
||||||
|
DefaultHTMLTemplate template = new DefaultHTMLTemplate(); |
||||||
|
|
||||||
|
String tableTypeMessage = template.getMessageFromTemplate(list2String(), ShowType.TABLE, true); |
||||||
|
|
||||||
|
assertEquals(tableTypeMessage, generateMockTableTypeResultByHand()); |
||||||
|
|
||||||
|
String textTypeMessage = template.getMessageFromTemplate(list2String(), ShowType.TEXT, true); |
||||||
|
|
||||||
|
assertEquals(textTypeMessage, generateMockTextTypeResultByHand()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* generate some simulation data |
||||||
|
*/ |
||||||
|
private String list2String() { |
||||||
|
|
||||||
|
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
||||||
|
map1.put("mysql service name", "mysql200"); |
||||||
|
map1.put("mysql address", "192.168.xx.xx"); |
||||||
|
map1.put("database client connections", "190"); |
||||||
|
map1.put("port", "3306"); |
||||||
|
map1.put("no index of number", "80"); |
||||||
|
|
||||||
|
LinkedHashMap<String, Object> map2 = new LinkedHashMap<>(); |
||||||
|
map2.put("mysql service name", "mysql210"); |
||||||
|
map2.put("mysql address", "192.168.xx.xx"); |
||||||
|
map2.put("database client connections", "90"); |
||||||
|
map2.put("port", "3306"); |
||||||
|
map2.put("no index of number", "10"); |
||||||
|
|
||||||
|
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
||||||
|
maps.add(0, map1); |
||||||
|
maps.add(1, map2); |
||||||
|
String mapjson = JSONUtils.toJsonString(maps); |
||||||
|
logger.info(mapjson); |
||||||
|
|
||||||
|
return mapjson; |
||||||
|
} |
||||||
|
|
||||||
|
private String generateMockTableTypeResultByHand() { |
||||||
|
|
||||||
|
return EmailConstants.HTML_HEADER_PREFIX |
||||||
|
+ "<thead>" |
||||||
|
+ "<tr><th>mysql service name</th><th>mysql address</th><th>database client connections</th><th>port</th><th>no index of number</th></tr>" |
||||||
|
+ "</thead>\n" |
||||||
|
+ "<tr><td>mysql200</td><td>192.168.xx.xx</td><td>190</td><td>3306</td><td>80</td></tr>" |
||||||
|
+ "<tr><td>mysql210</td><td>192.168.xx.xx</td><td>90</td><td>3306</td><td>10</td></tr>" |
||||||
|
+ EmailConstants.TABLE_BODY_HTML_TAIL; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private String generateMockTextTypeResultByHand() { |
||||||
|
|
||||||
|
return EmailConstants.HTML_HEADER_PREFIX |
||||||
|
+ "<tr><td>{\"mysql service name\":\"mysql200\",\"mysql address\":\"192.168.xx.xx\",\"database client connections\":\"190\",\"port\":\"3306\",\"no index of number\":\"80\"}</td></tr>" |
||||||
|
+ "<tr><td>{\"mysql service name\":\"mysql210\",\"mysql address\":\"192.168.xx.xx\",\"database client connections\":\"90\",\"port\":\"3306\",\"no index of number\":\"10\"}</td></tr>" |
||||||
|
+ EmailConstants.TABLE_BODY_HTML_TAIL; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<artifactId>dolphinscheduler-alert-http</artifactId> |
||||||
|
<packaging>dolphinscheduler-plugin</packaging> |
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-spi</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||||
|
<artifactId>httpclient</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-databind</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<type>jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>dolphinscheduler-alert-http-${project.version}</finalName> |
||||||
|
</build> |
||||||
|
|
||||||
|
</project> |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* http alert channel,use sms message to seed the alertInfo |
||||||
|
*/ |
||||||
|
public class HttpAlertChannel implements AlertChannel { |
||||||
|
@Override |
||||||
|
public AlertResult process(AlertInfo alertInfo) { |
||||||
|
|
||||||
|
AlertData alertData = alertInfo.getAlertData(); |
||||||
|
String alertParams = alertInfo.getAlertParams(); |
||||||
|
Map<String, String> paramsMap = PluginParamsTransfer.getPluginParamsMap(alertParams); |
||||||
|
|
||||||
|
return new HttpSender(paramsMap).send(alertData.getContent()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* http alert factory |
||||||
|
*/ |
||||||
|
public class HttpAlertChannelFactory implements AlertChannelFactory { |
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "Http"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<PluginParams> getParams() { |
||||||
|
|
||||||
|
InputParam url = InputParam.newBuilder(HttpAlertConstants.URL, HttpAlertConstants.URL) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam headerParams = InputParam.newBuilder(HttpAlertConstants.HEADER_PARAMS, HttpAlertConstants.HEADER_PARAMS) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam bodyParams = InputParam.newBuilder(HttpAlertConstants.BODY_PARAMS, HttpAlertConstants.BODY_PARAMS) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam contentField = InputParam.newBuilder(HttpAlertConstants.CONTENT_FIELD, HttpAlertConstants.CONTENT_FIELD) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam requestType = InputParam.newBuilder(HttpAlertConstants.REQUEST_TYPE, HttpAlertConstants.REQUEST_TYPE) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
return Arrays.asList(url, requestType, headerParams, bodyParams, contentField); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertChannel create() { |
||||||
|
return new HttpAlertChannel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
public class HttpAlertConstants { |
||||||
|
|
||||||
|
private HttpAlertConstants() { |
||||||
|
} |
||||||
|
|
||||||
|
public static final String URL = "url"; |
||||||
|
|
||||||
|
public static final String HEADER_PARAMS = "headerParams"; |
||||||
|
|
||||||
|
public static final String BODY_PARAMS = "bodyParams"; |
||||||
|
|
||||||
|
public static final String CONTENT_FIELD = "contentField"; |
||||||
|
|
||||||
|
public static final String REQUEST_TYPE = "requestType"; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* http alertPlugins |
||||||
|
*/ |
||||||
|
public class HttpAlertPlugin implements DolphinSchedulerPlugin { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterable<AlertChannelFactory> getAlertChannelFactorys() { |
||||||
|
return ImmutableList.of(new HttpAlertChannelFactory()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,166 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||||
|
|
||||||
|
import org.apache.http.HttpEntity; |
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse; |
||||||
|
import org.apache.http.client.methods.HttpGet; |
||||||
|
import org.apache.http.client.methods.HttpPost; |
||||||
|
import org.apache.http.client.methods.HttpRequestBase; |
||||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||||
|
import org.apache.http.impl.client.HttpClientBuilder; |
||||||
|
import org.apache.http.util.EntityUtils; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode; |
||||||
|
|
||||||
|
/** |
||||||
|
* http send message |
||||||
|
*/ |
||||||
|
public class HttpSender { |
||||||
|
|
||||||
|
public static final Logger logger = LoggerFactory.getLogger(HttpSender.class); |
||||||
|
|
||||||
|
private String url; |
||||||
|
|
||||||
|
private final String headerParams; |
||||||
|
|
||||||
|
private final String bodyParams; |
||||||
|
|
||||||
|
private final String contentField; |
||||||
|
|
||||||
|
private final String requestType; |
||||||
|
|
||||||
|
private HttpRequestBase httpRequest; |
||||||
|
|
||||||
|
|
||||||
|
private static final String URL_SPLICE_CHAR = "?"; |
||||||
|
|
||||||
|
/** |
||||||
|
* request type post |
||||||
|
*/ |
||||||
|
private static final String REQUEST_TYPE_POST = "POST"; |
||||||
|
|
||||||
|
/** |
||||||
|
* request type get |
||||||
|
*/ |
||||||
|
private static final String REQUEST_TYPE_GET = "GET"; |
||||||
|
|
||||||
|
private static final String DEFAULT_CHARSET = "utf-8"; |
||||||
|
|
||||||
|
public HttpSender(Map<String, String> paramsMap) { |
||||||
|
|
||||||
|
url = paramsMap.get(HttpAlertConstants.URL); |
||||||
|
headerParams = paramsMap.get(HttpAlertConstants.HEADER_PARAMS); |
||||||
|
bodyParams = paramsMap.get(HttpAlertConstants.BODY_PARAMS); |
||||||
|
contentField = paramsMap.get(HttpAlertConstants.CONTENT_FIELD); |
||||||
|
requestType = paramsMap.get(HttpAlertConstants.REQUEST_TYPE); |
||||||
|
} |
||||||
|
|
||||||
|
public AlertResult send(String msg) { |
||||||
|
|
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
|
||||||
|
createHttpRequest(msg); |
||||||
|
|
||||||
|
if (httpRequest == null) { |
||||||
|
alertResult.setStatus("false"); |
||||||
|
alertResult.setMessage("Request types are not supported"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
||||||
|
CloseableHttpResponse response = httpClient.execute(httpRequest); |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
String resp = EntityUtils.toString(entity, DEFAULT_CHARSET); |
||||||
|
alertResult.setStatus("true"); |
||||||
|
alertResult.setMessage(resp); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("send http alert msg exception : {}", e.getMessage()); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
alertResult.setMessage("send http request alert fail."); |
||||||
|
} |
||||||
|
|
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
private void createHttpRequest(String msg) { |
||||||
|
|
||||||
|
if (REQUEST_TYPE_POST.equals(requestType)) { |
||||||
|
httpRequest = new HttpPost(url); |
||||||
|
//POST request add param in request body
|
||||||
|
setMsgInRequestBody(msg); |
||||||
|
} else if (REQUEST_TYPE_GET.equals(requestType)) { |
||||||
|
//GET request add param in url
|
||||||
|
setMsgInUrl(msg); |
||||||
|
httpRequest = new HttpGet(url); |
||||||
|
} |
||||||
|
setHeader(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* add msg param in url |
||||||
|
*/ |
||||||
|
private void setMsgInUrl(String msg) { |
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(contentField)) { |
||||||
|
String type = "&"; |
||||||
|
//check splice char is & or ?
|
||||||
|
if (!url.contains(URL_SPLICE_CHAR)) { |
||||||
|
type = URL_SPLICE_CHAR; |
||||||
|
} |
||||||
|
url = String.format("%s%s%s=%s", url, type, contentField, msg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* set header params |
||||||
|
*/ |
||||||
|
private void setHeader() { |
||||||
|
|
||||||
|
if (httpRequest == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
HashMap<String, Object> map = JSONUtils.parseObject(headerParams, HashMap.class); |
||||||
|
for (Map.Entry<String, Object> entry : map.entrySet()) { |
||||||
|
httpRequest.setHeader(entry.getKey(), String.valueOf(entry.getValue())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* set body params |
||||||
|
*/ |
||||||
|
private String setMsgInRequestBody(String msg) { |
||||||
|
ObjectNode objectNode = JSONUtils.parseObject(bodyParams); |
||||||
|
//set msg content field
|
||||||
|
objectNode.put(contentField, msg); |
||||||
|
return objectNode.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* HttpAlertChannel UT |
||||||
|
*/ |
||||||
|
public class HttpAlertChannelTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void processTest() { |
||||||
|
|
||||||
|
HttpAlertChannel alertChannel = new HttpAlertChannel(); |
||||||
|
AlertInfo alertInfo = new AlertInfo(); |
||||||
|
AlertData alertData = new AlertData(); |
||||||
|
alertData.setContent("Fault tolerance warning"); |
||||||
|
alertInfo.setAlertData(alertData); |
||||||
|
AlertResult alertResult = alertChannel.process(alertInfo); |
||||||
|
Assert.assertEquals("Request types are not supported", alertResult.getMessage()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void processTest2() { |
||||||
|
|
||||||
|
HttpAlertChannel alertChannel = new HttpAlertChannel(); |
||||||
|
AlertInfo alertInfo = new AlertInfo(); |
||||||
|
AlertData alertData = new AlertData(); |
||||||
|
alertData.setContent("Fault tolerance warning"); |
||||||
|
alertInfo.setAlertData(alertData); |
||||||
|
alertInfo.setAlertParams(getParams()); |
||||||
|
AlertResult alertResult = alertChannel.process(alertInfo); |
||||||
|
Assert.assertEquals("true", alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create params |
||||||
|
*/ |
||||||
|
private String getParams() { |
||||||
|
|
||||||
|
List<PluginParams> paramsList = new ArrayList<>(); |
||||||
|
InputParam urlParam = InputParam.newBuilder("url", "url") |
||||||
|
.setValue("http://www.baidu.com") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam headerParams = InputParam.newBuilder("headerParams", "headerParams") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue("{\"Content-Type\":\"application/json\"}") |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam bodyParams = InputParam.newBuilder("bodyParams", "bodyParams") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.setValue("{\"number\":\"13457654323\"}") |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam content = InputParam.newBuilder("contentField", "contentField") |
||||||
|
.setValue("content") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam requestType = InputParam.newBuilder("requestType", "requestType") |
||||||
|
.setValue("POST") |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
paramsList.add(urlParam); |
||||||
|
paramsList.add(headerParams); |
||||||
|
paramsList.add(bodyParams); |
||||||
|
paramsList.add(content); |
||||||
|
paramsList.add(requestType); |
||||||
|
|
||||||
|
return JSONUtils.toJsonString(paramsList); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* HttpAlertPlugin UT |
||||||
|
*/ |
||||||
|
public class HttpAlertPluginTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void getAlertChannelFactorysTest() { |
||||||
|
|
||||||
|
HttpAlertPlugin httpAlertPlugin = new HttpAlertPlugin(); |
||||||
|
Iterable<AlertChannelFactory> alertChannelFactorys = httpAlertPlugin.getAlertChannelFactorys(); |
||||||
|
Assert.assertNotNull(alertChannelFactorys); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.http; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* HttpSender UT |
||||||
|
*/ |
||||||
|
public class HttpSenderTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void sendTest() { |
||||||
|
|
||||||
|
Map<String, String> paramsMap = new HashMap<>(); |
||||||
|
paramsMap.put(HttpAlertConstants.URL, "http://www.baidu.com"); |
||||||
|
paramsMap.put(HttpAlertConstants.REQUEST_TYPE, "POST"); |
||||||
|
paramsMap.put(HttpAlertConstants.HEADER_PARAMS, "{\"Content-Type\":\"application/json\"}"); |
||||||
|
paramsMap.put(HttpAlertConstants.BODY_PARAMS, "{\"number\":\"13457654323\"}"); |
||||||
|
paramsMap.put(HttpAlertConstants.CONTENT_FIELD, "content"); |
||||||
|
HttpSender httpSender = new HttpSender(paramsMap); |
||||||
|
AlertResult alertResult = httpSender.send("Fault tolerance warning"); |
||||||
|
Assert.assertEquals("true", alertResult.getStatus()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-alert-script</artifactId> |
||||||
|
<packaging>dolphinscheduler-plugin</packaging> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-spi</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.slf4j</groupId> |
||||||
|
<artifactId>slf4j-api</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-annotations</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<type>jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>dolphinscheduler-alert-script-${project.version}</finalName> |
||||||
|
</build> |
||||||
|
|
||||||
|
</project> |
@ -0,0 +1,32 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
/** |
||||||
|
* OSUtils |
||||||
|
*/ |
||||||
|
public class OSUtils { |
||||||
|
|
||||||
|
public OSUtils() { |
||||||
|
throw new UnsupportedOperationException("Construct OSUtils"); |
||||||
|
} |
||||||
|
|
||||||
|
static Boolean isWindows() { |
||||||
|
return System.getProperty("os.name").startsWith("Windows"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,62 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* ProcessUtils |
||||||
|
*/ |
||||||
|
public class ProcessUtils { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class); |
||||||
|
|
||||||
|
private ProcessUtils() { |
||||||
|
throw new IllegalStateException("Utility class"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* executeScript |
||||||
|
* |
||||||
|
* @param cmd cmd params |
||||||
|
* @return exit code |
||||||
|
*/ |
||||||
|
static Integer executeScript(String... cmd) { |
||||||
|
|
||||||
|
int exitCode = -1; |
||||||
|
|
||||||
|
ProcessBuilder processBuilder = new ProcessBuilder(cmd); |
||||||
|
try { |
||||||
|
Process process = processBuilder.start(); |
||||||
|
StreamGobbler inputStreamGobbler = new StreamGobbler(process.getInputStream()); |
||||||
|
StreamGobbler errorStreamGobbler = new StreamGobbler(process.getErrorStream()); |
||||||
|
|
||||||
|
inputStreamGobbler.start(); |
||||||
|
errorStreamGobbler.start(); |
||||||
|
return process.waitFor(); |
||||||
|
} catch (IOException | InterruptedException e) { |
||||||
|
logger.error("execute alert script error {}", e.getMessage()); |
||||||
|
Thread.currentThread().interrupt(); |
||||||
|
} |
||||||
|
|
||||||
|
return exitCode; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptAlertChannel |
||||||
|
*/ |
||||||
|
public class ScriptAlertChannel implements AlertChannel { |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertResult process(AlertInfo alertinfo) { |
||||||
|
AlertData alertData = alertinfo.getAlertData(); |
||||||
|
String alertParams = alertinfo.getAlertParams(); |
||||||
|
Map<String, String> paramsMap = PluginParamsTransfer.getPluginParamsMap(alertParams); |
||||||
|
return new ScriptSender(paramsMap).sendScriptAlert(alertData.getTitle()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.RadioParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptAlertChannelFactory |
||||||
|
*/ |
||||||
|
public class ScriptAlertChannelFactory implements AlertChannelFactory { |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "Script"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<PluginParams> getParams() { |
||||||
|
|
||||||
|
InputParam scriptUserParam = InputParam.newBuilder(ScriptParamsConstants.NAME_SCRIPT_USER_PARAMS, ScriptParamsConstants.SCRIPT_USER_PARAMS) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(false) |
||||||
|
.build()) |
||||||
|
.setPlaceholder("please enter your custom parameters, which will be passed to you when calling your script") |
||||||
|
.build(); |
||||||
|
// need check file type and file exist
|
||||||
|
InputParam scriptPathParam = InputParam.newBuilder(ScriptParamsConstants.NAME_SCRIPT_PATH, ScriptParamsConstants.SCRIPT_PATH) |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.setPlaceholder("please upload the file to the disk directory of the alert server, and ensure that the path is absolute and has the corresponding access rights") |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam scriptTypeParams = RadioParam.newBuilder(ScriptParamsConstants.NAME_SCRIPT_TYPE, ScriptParamsConstants.SCRIPT_TYPE) |
||||||
|
.addParamsOptions(new ParamsOptions(ScriptType.SHELL.getDescp(), ScriptType.SHELL.getCode(), false)) |
||||||
|
.setValue(ScriptType.SHELL.getCode()) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
return Arrays.asList(scriptUserParam, scriptPathParam, scriptTypeParams); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertChannel create() { |
||||||
|
return new ScriptAlertChannel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptAlertPlugin |
||||||
|
*/ |
||||||
|
public class ScriptAlertPlugin implements DolphinSchedulerPlugin { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterable<AlertChannelFactory> getAlertChannelFactorys() { |
||||||
|
return ImmutableList.of(new ScriptAlertChannelFactory()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptParamsConstants |
||||||
|
*/ |
||||||
|
public class ScriptParamsConstants { |
||||||
|
|
||||||
|
public ScriptParamsConstants() { |
||||||
|
throw new IllegalStateException("Utility class"); |
||||||
|
} |
||||||
|
|
||||||
|
static final String SCRIPT_TYPE = "type"; |
||||||
|
|
||||||
|
static final String NAME_SCRIPT_TYPE = "type"; |
||||||
|
|
||||||
|
static final String SCRIPT_PATH = "path"; |
||||||
|
|
||||||
|
static final String NAME_SCRIPT_PATH = "path"; |
||||||
|
|
||||||
|
static final String SCRIPT_USER_PARAMS = "user.params"; |
||||||
|
|
||||||
|
static final String NAME_SCRIPT_USER_PARAMS = "userParams"; |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptSender |
||||||
|
*/ |
||||||
|
public class ScriptSender { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ScriptSender.class); |
||||||
|
|
||||||
|
private String scriptPath; |
||||||
|
|
||||||
|
private Integer scriptType; |
||||||
|
|
||||||
|
private String userParams; |
||||||
|
|
||||||
|
ScriptSender(Map<String, String> config) { |
||||||
|
scriptPath = config.get(ScriptParamsConstants.NAME_SCRIPT_PATH); |
||||||
|
scriptType = Integer.parseInt(config.get(ScriptParamsConstants.NAME_SCRIPT_TYPE)); |
||||||
|
userParams = config.get(ScriptParamsConstants.NAME_SCRIPT_USER_PARAMS); |
||||||
|
} |
||||||
|
|
||||||
|
AlertResult sendScriptAlert(String msg) { |
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
if (ScriptType.of(scriptType).equals(ScriptType.SHELL)) { |
||||||
|
return executeShellScript(msg); |
||||||
|
} |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
private AlertResult executeShellScript(String msg) { |
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
if (Boolean.TRUE.equals(OSUtils.isWindows())) { |
||||||
|
alertResult.setMessage("shell script not support windows os"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
String[] cmd = {"/bin/sh", "-c", scriptPath + " " + msg + " " + userParams}; |
||||||
|
int exitCode = ProcessUtils.executeScript(cmd); |
||||||
|
|
||||||
|
if (exitCode == 0) { |
||||||
|
alertResult.setStatus("true"); |
||||||
|
alertResult.setMessage("send script alert msg success"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
alertResult.setMessage("send script alert msg error,exitCode is " + exitCode); |
||||||
|
logger.info("send script alert msg error,exitCode is {}", exitCode); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* ProcessUtilsTest |
||||||
|
*/ |
||||||
|
public class ProcessUtilsTest { |
||||||
|
|
||||||
|
private static final String rootPath = System.getProperty("user.dir"); |
||||||
|
|
||||||
|
private static final String shellFilPath = rootPath + "/dolphinscheduler-alert-plugin/dolphinscheduler-alert-script/src/test/script/shell/example.sh"; |
||||||
|
|
||||||
|
private String[] cmd = {"/bin/sh", "-c", shellFilPath + " " + "testMsg" + " " + "userParams"}; |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testExecuteScript() { |
||||||
|
ProcessUtils.executeScript(cmd); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptAlertChannelFactoryTest |
||||||
|
*/ |
||||||
|
public class ScriptAlertChannelFactoryTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testGetParams() { |
||||||
|
ScriptAlertChannelFactory scriptAlertChannelFactory = new ScriptAlertChannelFactory(); |
||||||
|
List<PluginParams> params = scriptAlertChannelFactory.getParams(); |
||||||
|
JSONUtils.toJsonString(params); |
||||||
|
Assert.assertEquals(3, params.size()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCreate() { |
||||||
|
ScriptAlertChannelFactory scriptAlertChannelFactory = new ScriptAlertChannelFactory(); |
||||||
|
AlertChannel alertChannel = scriptAlertChannelFactory.create(); |
||||||
|
Assert.assertNotNull(alertChannel); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.script; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* ScriptSenderTest |
||||||
|
*/ |
||||||
|
public class ScriptSenderTest { |
||||||
|
|
||||||
|
private static Map<String, String> scriptConfig = new HashMap<>(); |
||||||
|
|
||||||
|
private static final String rootPath = System.getProperty("user.dir"); |
||||||
|
|
||||||
|
private static final String shellFilPath = rootPath + "/src/test/script/shell/scriptTest.sh"; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void initScriptConfig() { |
||||||
|
|
||||||
|
scriptConfig.put(ScriptParamsConstants.NAME_SCRIPT_TYPE, String.valueOf(ScriptType.SHELL.getCode())); |
||||||
|
scriptConfig.put(ScriptParamsConstants.NAME_SCRIPT_USER_PARAMS, "userParams"); |
||||||
|
scriptConfig.put(ScriptParamsConstants.NAME_SCRIPT_PATH, shellFilPath); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testScriptSenderTest() { |
||||||
|
ScriptSender scriptSender = new ScriptSender(scriptConfig); |
||||||
|
AlertResult alertResult; |
||||||
|
alertResult = scriptSender.sendScriptAlert("success"); |
||||||
|
Assert.assertEquals("true", alertResult.getStatus()); |
||||||
|
alertResult = scriptSender.sendScriptAlert("errorMsg"); |
||||||
|
Assert.assertEquals("false", alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
# |
||||||
|
# Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
# contributor license agreements. See the NOTICE file distributed with |
||||||
|
# this work for additional information regarding copyright ownership. |
||||||
|
# The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
# (the "License"); you may not use this file except in compliance with |
||||||
|
# the License. You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
# |
||||||
|
|
||||||
|
|
||||||
|
msg=$1 |
||||||
|
content=$2 |
||||||
|
|
||||||
|
# Write your specific logic here |
||||||
|
|
||||||
|
# Set the exit code according to your execution result, and alert needs to use it to judge the status of this alarm result |
||||||
|
exit 0 |
@ -0,0 +1,78 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-alert-wechat</artifactId> |
||||||
|
<packaging>dolphinscheduler-plugin</packaging> |
||||||
|
<dependencies> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-spi</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.google.guava</groupId> |
||||||
|
<artifactId>guava</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>ch.qos.logback</groupId> |
||||||
|
<artifactId>logback-classic</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.apache.httpcomponents</groupId> |
||||||
|
<artifactId>httpclient</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.fasterxml.jackson.core</groupId> |
||||||
|
<artifactId>jackson-databind</artifactId> |
||||||
|
<scope>provided</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>junit</groupId> |
||||||
|
<artifactId>junit</artifactId> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.mockito</groupId> |
||||||
|
<artifactId>mockito-core</artifactId> |
||||||
|
<type>jar</type> |
||||||
|
<scope>test</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<finalName>dolphinscheduler-alert-wechat-${project.version}</finalName> |
||||||
|
</build> |
||||||
|
</project> |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertData; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertInfo; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertChannel |
||||||
|
*/ |
||||||
|
public class WeChatAlertChannel implements AlertChannel { |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertResult process(AlertInfo info) { |
||||||
|
AlertData alertData = info.getAlertData(); |
||||||
|
String alertParams = info.getAlertParams(); |
||||||
|
Map<String, String> paramsMap = PluginParamsTransfer.getPluginParamsMap(alertParams); |
||||||
|
return new WeChatSender(paramsMap).sendEnterpriseWeChat(alertData.getTitle(), alertData.getContent()); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,94 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.params.InputParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.RadioParam; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.Validate; |
||||||
|
|
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertChannelFactory |
||||||
|
*/ |
||||||
|
public class WeChatAlertChannelFactory implements AlertChannelFactory { |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getName() { |
||||||
|
return "WeChat"; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<PluginParams> getParams() { |
||||||
|
InputParam corpIdParam = InputParam.newBuilder(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_CORP_ID, WeChatAlertParamsConstants.ENTERPRISE_WE_CHAT_CORP_ID) |
||||||
|
.setPlaceholder("please input corp id ") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam secretParam = InputParam.newBuilder(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_SECRET, WeChatAlertParamsConstants.ENTERPRISE_WE_CHAT_SECRET) |
||||||
|
.setPlaceholder("please input secret ") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam usersParam = InputParam.newBuilder(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USERS, WeChatAlertParamsConstants.ENTERPRISE_WE_CHAT_USERS) |
||||||
|
.setPlaceholder("please input users ") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam userSendMsgParam = InputParam.newBuilder(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USER_SEND_MSG, WeChatAlertParamsConstants.ENTERPRISE_WE_CHAT_USER_SEND_MSG) |
||||||
|
.setPlaceholder("please input corp id ") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
InputParam agentIdParam = InputParam.newBuilder(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_AGENT_ID, WeChatAlertParamsConstants.ENTERPRISE_WE_CHAT_AGENT_ID) |
||||||
|
.setPlaceholder("please input agent id ") |
||||||
|
.addValidate(Validate.newBuilder() |
||||||
|
.setRequired(true) |
||||||
|
.build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
RadioParam showType = RadioParam.newBuilder(AlertConstants.SHOW_TYPE, AlertConstants.SHOW_TYPE) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.TABLE.getDescp(), ShowType.TABLE.getDescp(), false)) |
||||||
|
.addParamsOptions(new ParamsOptions(ShowType.TEXT.getDescp(), ShowType.TEXT.getDescp(), false)) |
||||||
|
.setValue(ShowType.TABLE.getDescp()) |
||||||
|
.addValidate(Validate.newBuilder().setRequired(true).build()) |
||||||
|
.build(); |
||||||
|
|
||||||
|
return Arrays.asList(corpIdParam, secretParam, usersParam, userSendMsgParam, agentIdParam, showType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AlertChannel create() { |
||||||
|
return new WeChatAlertChannel(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertConstants |
||||||
|
*/ |
||||||
|
public class WeChatAlertConstants { |
||||||
|
|
||||||
|
static final String MARKDOWN_QUOTE = ">"; |
||||||
|
|
||||||
|
static final String MARKDOWN_ENTER = "\n"; |
||||||
|
|
||||||
|
static final String CHARSET = "UTF-8"; |
||||||
|
|
||||||
|
static final String WE_CHAT_PUSH_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={token}"; |
||||||
|
|
||||||
|
static final String WE_CHAT_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpId}&corpsecret={secret}"; |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertParamsConstants |
||||||
|
*/ |
||||||
|
public class WeChatAlertParamsConstants { |
||||||
|
|
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_CORP_ID = "corp.id"; |
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_CORP_ID = "corpId"; |
||||||
|
|
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_SECRET = "secret"; |
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_SECRET = "secret"; |
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_TEAM_SEND_MSG = "team.send.msg"; |
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_TEAM_SEND_MSG = "teamSendMsg"; |
||||||
|
|
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_USER_SEND_MSG = "user.send.msg"; |
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_USER_SEND_MSG = "userSendMsg"; |
||||||
|
|
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_AGENT_ID = "agent.id"; |
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_AGENT_ID = "agentId"; |
||||||
|
|
||||||
|
|
||||||
|
static final String ENTERPRISE_WE_CHAT_USERS = "users"; |
||||||
|
|
||||||
|
|
||||||
|
static final String NAME_ENTERPRISE_WE_CHAT_USERS = "users"; |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertPlugin |
||||||
|
*/ |
||||||
|
public class WeChatAlertPlugin implements DolphinSchedulerPlugin { |
||||||
|
|
||||||
|
@Override |
||||||
|
public Iterable<AlertChannelFactory> getAlertChannelFactorys() { |
||||||
|
return ImmutableList.of(new WeChatAlertChannelFactory()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,335 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||||
|
|
||||||
|
import org.apache.http.HttpEntity; |
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse; |
||||||
|
import org.apache.http.client.methods.HttpGet; |
||||||
|
import org.apache.http.client.methods.HttpPost; |
||||||
|
import org.apache.http.entity.StringEntity; |
||||||
|
import org.apache.http.impl.client.CloseableHttpClient; |
||||||
|
import org.apache.http.impl.client.HttpClients; |
||||||
|
import org.apache.http.util.EntityUtils; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Map.Entry; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatSender |
||||||
|
*/ |
||||||
|
public class WeChatSender { |
||||||
|
|
||||||
|
private static Logger logger = LoggerFactory.getLogger(WeChatSender.class); |
||||||
|
|
||||||
|
private String weChatAgentId; |
||||||
|
|
||||||
|
private String weChatUsers; |
||||||
|
|
||||||
|
private String weChatTeamSendMsg; |
||||||
|
|
||||||
|
private String weChatUserSendMsg; |
||||||
|
|
||||||
|
private String weChatTokenUrlReplace; |
||||||
|
|
||||||
|
private String weChatToken; |
||||||
|
|
||||||
|
private String showType; |
||||||
|
|
||||||
|
|
||||||
|
private static final String agentIdRegExp = "{agentId}"; |
||||||
|
private static final String msgRegExp = "{msg}"; |
||||||
|
private static final String userRegExp = "{toUser}"; |
||||||
|
private static final String corpIdRegex = "{corpId}"; |
||||||
|
private static final String secretRegex = "{secret}"; |
||||||
|
private static final String toPartyRegex = "{toParty}"; |
||||||
|
private static final String toUserRegex = "{toUser}"; |
||||||
|
private static final String tokenRegex = "{token}"; |
||||||
|
|
||||||
|
WeChatSender(Map<String, String> config) { |
||||||
|
weChatAgentId = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_AGENT_ID); |
||||||
|
weChatUsers = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USERS); |
||||||
|
String weChatCorpId = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_CORP_ID); |
||||||
|
String weChatSecret = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_SECRET); |
||||||
|
String weChatTokenUrl = WeChatAlertConstants.WE_CHAT_TOKEN_URL; |
||||||
|
weChatTeamSendMsg = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_TEAM_SEND_MSG); |
||||||
|
weChatUserSendMsg = config.get(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USER_SEND_MSG); |
||||||
|
showType = config.get(AlertConstants.SHOW_TYPE); |
||||||
|
requireNonNull(showType, AlertConstants.SHOW_TYPE + " must not null"); |
||||||
|
weChatTokenUrlReplace = weChatTokenUrl |
||||||
|
.replace(corpIdRegex, weChatCorpId) |
||||||
|
.replace(secretRegex, weChatSecret); |
||||||
|
weChatToken = getToken(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* make user multi user message |
||||||
|
* |
||||||
|
* @param toUser the toUser |
||||||
|
* @param agentId the agentId |
||||||
|
* @param msg the msg |
||||||
|
* @return Enterprise WeChat send message |
||||||
|
*/ |
||||||
|
private String makeUserSendMsg(Collection<String> toUser, String agentId, String msg) { |
||||||
|
String listUser = mkString(toUser); |
||||||
|
return weChatUserSendMsg.replace(userRegExp, listUser) |
||||||
|
.replace(agentIdRegExp, agentId) |
||||||
|
.replace(msgRegExp, msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* send Enterprise WeChat |
||||||
|
* |
||||||
|
* @return Enterprise WeChat resp, demo: {"errcode":0,"errmsg":"ok","invaliduser":""} |
||||||
|
* @throws Exception the Exception |
||||||
|
*/ |
||||||
|
public AlertResult sendEnterpriseWeChat(String title, String content) { |
||||||
|
AlertResult alertResult; |
||||||
|
List<String> userList = Arrays.asList(weChatUsers.split(",")); |
||||||
|
String data = markdownByAlert(title, content); |
||||||
|
String msg = makeUserSendMsg(userList, weChatAgentId, data); |
||||||
|
if (null == weChatToken) { |
||||||
|
alertResult = new AlertResult(); |
||||||
|
alertResult.setMessage("send we chat alert fail,get weChat token error"); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
String enterpriseWeChatPushUrlReplace = WeChatAlertConstants.WE_CHAT_PUSH_URL.replace(tokenRegex, weChatToken); |
||||||
|
|
||||||
|
try { |
||||||
|
return checkWeChatSendMsgResult(post(enterpriseWeChatPushUrlReplace, msg)); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.info("send we chat alert msg exception : {}", e.getMessage()); |
||||||
|
alertResult = new AlertResult(); |
||||||
|
alertResult.setMessage("send we chat alert fail"); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
} |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
|
||||||
|
private static String post(String url, String data) throws IOException { |
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { |
||||||
|
HttpPost httpPost = new HttpPost(url); |
||||||
|
httpPost.setEntity(new StringEntity(data, WeChatAlertConstants.CHARSET)); |
||||||
|
CloseableHttpResponse response = httpClient.execute(httpPost); |
||||||
|
String resp; |
||||||
|
try { |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
resp = EntityUtils.toString(entity, WeChatAlertConstants.CHARSET); |
||||||
|
EntityUtils.consume(entity); |
||||||
|
} finally { |
||||||
|
response.close(); |
||||||
|
} |
||||||
|
logger.info("Enterprise WeChat send [{}], param:{}, resp:{}", |
||||||
|
url, data, resp); |
||||||
|
return resp; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* convert table to markdown style |
||||||
|
* |
||||||
|
* @param title the title |
||||||
|
* @param content the content |
||||||
|
* @return markdown table content |
||||||
|
*/ |
||||||
|
private static String markdownTable(String title, String content) { |
||||||
|
List<LinkedHashMap> mapItemsList = JSONUtils.toList(content, LinkedHashMap.class); |
||||||
|
if (null == mapItemsList || mapItemsList.isEmpty()) { |
||||||
|
logger.error("itemsList is null"); |
||||||
|
throw new RuntimeException("itemsList is null"); |
||||||
|
} |
||||||
|
StringBuilder contents = new StringBuilder(200); |
||||||
|
for (LinkedHashMap mapItems : mapItemsList) { |
||||||
|
Set<Entry<String, Object>> entries = mapItems.entrySet(); |
||||||
|
Iterator<Entry<String, Object>> iterator = entries.iterator(); |
||||||
|
StringBuilder t = new StringBuilder(String.format("`%s`%s", title, WeChatAlertConstants.MARKDOWN_ENTER)); |
||||||
|
|
||||||
|
while (iterator.hasNext()) { |
||||||
|
|
||||||
|
Map.Entry<String, Object> entry = iterator.next(); |
||||||
|
t.append(WeChatAlertConstants.MARKDOWN_QUOTE); |
||||||
|
t.append(entry.getKey()).append(":").append(entry.getValue()); |
||||||
|
t.append(WeChatAlertConstants.MARKDOWN_ENTER); |
||||||
|
} |
||||||
|
contents.append(t); |
||||||
|
} |
||||||
|
|
||||||
|
return contents.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* convert text to markdown style |
||||||
|
* |
||||||
|
* @param title the title |
||||||
|
* @param content the content |
||||||
|
* @return markdown text |
||||||
|
*/ |
||||||
|
private static String markdownText(String title, String content) { |
||||||
|
if (StringUtils.isNotEmpty(content)) { |
||||||
|
List<LinkedHashMap> mapItemsList = JSONUtils.toList(content, LinkedHashMap.class); |
||||||
|
if (null == mapItemsList || mapItemsList.isEmpty()) { |
||||||
|
logger.error("itemsList is null"); |
||||||
|
throw new RuntimeException("itemsList is null"); |
||||||
|
} |
||||||
|
|
||||||
|
StringBuilder contents = new StringBuilder(100); |
||||||
|
contents.append(String.format("`%s`%n", title)); |
||||||
|
for (LinkedHashMap mapItems : mapItemsList) { |
||||||
|
|
||||||
|
Set<Map.Entry<String, Object>> entries = mapItems.entrySet(); |
||||||
|
for (Entry<String, Object> entry : entries) { |
||||||
|
contents.append(WeChatAlertConstants.MARKDOWN_QUOTE); |
||||||
|
contents.append(entry.getKey()).append(":").append(entry.getValue()); |
||||||
|
contents.append(WeChatAlertConstants.MARKDOWN_ENTER); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
return contents.toString(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determine the mardown style based on the show type of the alert |
||||||
|
* |
||||||
|
* @return the markdown alert table/text |
||||||
|
*/ |
||||||
|
private String markdownByAlert(String title, String content) { |
||||||
|
String result = ""; |
||||||
|
if (showType.equals(ShowType.TABLE.getDescp())) { |
||||||
|
result = markdownTable(title, content); |
||||||
|
} else if (showType.equals(ShowType.TEXT.getDescp())) { |
||||||
|
result = markdownText(title, content); |
||||||
|
} |
||||||
|
return result; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private String getToken() { |
||||||
|
try { |
||||||
|
return get(weChatTokenUrlReplace); |
||||||
|
} catch (IOException e) { |
||||||
|
logger.info("we chat alert get token error{}", e.getMessage()); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private static String get(String url) throws IOException { |
||||||
|
String resp; |
||||||
|
|
||||||
|
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { |
||||||
|
HttpGet httpGet = new HttpGet(url); |
||||||
|
try (CloseableHttpResponse response = httpClient.execute(httpGet)) { |
||||||
|
HttpEntity entity = response.getEntity(); |
||||||
|
resp = EntityUtils.toString(entity, WeChatAlertConstants.CHARSET); |
||||||
|
EntityUtils.consume(entity); |
||||||
|
} |
||||||
|
|
||||||
|
HashMap map = JSONUtils.parseObject(resp, HashMap.class); |
||||||
|
if (map != null && null != map.get("access_token")) { |
||||||
|
return map.get("access_token").toString(); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static String mkString(Iterable<String> list) { |
||||||
|
|
||||||
|
if (null == list || StringUtils.isEmpty("|")) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
boolean first = true; |
||||||
|
for (String item : list) { |
||||||
|
if (first) { |
||||||
|
first = false; |
||||||
|
} else { |
||||||
|
sb.append("|"); |
||||||
|
} |
||||||
|
sb.append(item); |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public static class WeChatSendMsgResponse { |
||||||
|
private Integer errcode; |
||||||
|
private String errmsg; |
||||||
|
|
||||||
|
public Integer getErrcode() { |
||||||
|
return errcode; |
||||||
|
} |
||||||
|
|
||||||
|
public void setErrcode(Integer errcode) { |
||||||
|
this.errcode = errcode; |
||||||
|
} |
||||||
|
|
||||||
|
public String getErrmsg() { |
||||||
|
return errmsg; |
||||||
|
} |
||||||
|
|
||||||
|
public void setErrmsg(String errmsg) { |
||||||
|
this.errmsg = errmsg; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static AlertResult checkWeChatSendMsgResult(String result) { |
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus("false"); |
||||||
|
|
||||||
|
if (null == result) { |
||||||
|
alertResult.setMessage("we chat send fail"); |
||||||
|
logger.info("send we chat msg error,resp is null"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
WeChatSendMsgResponse sendMsgResponse = JSONUtils.parseObject(result, WeChatSendMsgResponse.class); |
||||||
|
if (null == sendMsgResponse) { |
||||||
|
alertResult.setMessage("we chat send fail"); |
||||||
|
logger.info("send we chat msg error,resp error"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
if (sendMsgResponse.errcode == 0) { |
||||||
|
alertResult.setStatus("true"); |
||||||
|
alertResult.setMessage("we chat alert send success"); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
alertResult.setStatus("false"); |
||||||
|
alertResult.setMessage(sendMsgResponse.getErrmsg()); |
||||||
|
return alertResult; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatAlertChannelFactoryTest |
||||||
|
*/ |
||||||
|
public class WeChatAlertChannelFactoryTest { |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testGetParams() { |
||||||
|
WeChatAlertChannelFactory weChatAlertChannelFactory = new WeChatAlertChannelFactory(); |
||||||
|
List<PluginParams> params = weChatAlertChannelFactory.getParams(); |
||||||
|
JSONUtils.toJsonString(params); |
||||||
|
Assert.assertEquals(6, params.size()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testCreate() { |
||||||
|
WeChatAlertChannelFactory dingTalkAlertChannelFactory = new WeChatAlertChannelFactory(); |
||||||
|
AlertChannel alertChannel = dingTalkAlertChannelFactory.create(); |
||||||
|
Assert.assertNotNull(alertChannel); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.plugin.alert.wechat; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertConstants; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.ShowType; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/** |
||||||
|
* WeChatSenderTest |
||||||
|
*/ |
||||||
|
public class WeChatSenderTest { |
||||||
|
|
||||||
|
private static Map<String, String> weChatConfig = new HashMap<>(); |
||||||
|
|
||||||
|
private String content = "[{\"id\":\"69\"," |
||||||
|
+ |
||||||
|
"\"name\":\"UserBehavior-0--1193959466\"," |
||||||
|
+ |
||||||
|
"\"Job name\":\"Start workflow\"," |
||||||
|
+ |
||||||
|
"\"State\":\"SUCCESS\"," |
||||||
|
+ |
||||||
|
"\"Recovery\":\"NO\"," |
||||||
|
+ |
||||||
|
"\"Run time\":\"1\"," |
||||||
|
+ |
||||||
|
"\"Start time\": \"2018-08-06 10:31:34.0\"," |
||||||
|
+ |
||||||
|
"\"End time\": \"2018-08-06 10:31:49.0\"," |
||||||
|
+ |
||||||
|
"\"Host\": \"192.168.xx.xx\"," |
||||||
|
+ |
||||||
|
"\"Notify group\" :\"4\"}]"; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void initDingTalkConfig() { |
||||||
|
// Just for this test, I will delete these configurations before this PR is merged
|
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_AGENT_ID, "100000"); |
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_CORP_ID, "NAME_ENTERPRISE_WE_CHAT_CORP_ID"); |
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_SECRET, "NAME_ENTERPRISE_WE_CHAT_SECRET"); |
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USER_SEND_MSG, "{\"touser\":\"{toUser}\",\"agentid\":{agentId}" |
||||||
|
+ |
||||||
|
",\"msgtype\":\"markdown\",\"markdown\":{\"content\":\"{msg}\"}}" |
||||||
|
); |
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_USERS, "Kris"); |
||||||
|
weChatConfig.put(WeChatAlertParamsConstants.NAME_ENTERPRISE_WE_CHAT_TEAM_SEND_MSG, "msg"); |
||||||
|
weChatConfig.put(AlertConstants.SHOW_TYPE, ShowType.TABLE.getDescp()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendWeChatTableMsg() { |
||||||
|
WeChatSender weChatSender = new WeChatSender(weChatConfig); |
||||||
|
|
||||||
|
AlertResult alertResult = weChatSender.sendEnterpriseWeChat("test", content); |
||||||
|
Assert.assertEquals("false", alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSendWeChatTextMsg() { |
||||||
|
weChatConfig.put(AlertConstants.SHOW_TYPE, ShowType.TEXT.getDescp()); |
||||||
|
WeChatSender weChatSender = new WeChatSender(weChatConfig); |
||||||
|
AlertResult alertResult = weChatSender.sendEnterpriseWeChat("test", content); |
||||||
|
Assert.assertEquals("false", alertResult.getStatus()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!-- |
||||||
|
~ Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
~ contributor license agreements. See the NOTICE file distributed with |
||||||
|
~ this work for additional information regarding copyright ownership. |
||||||
|
~ The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
~ (the "License"); you may not use this file except in compliance with |
||||||
|
~ the License. You may obtain a copy of the License at |
||||||
|
~ |
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
~ |
||||||
|
~ Unless required by applicable law or agreed to in writing, software |
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
~ See the License for the specific language governing permissions and |
||||||
|
~ limitations under the License. |
||||||
|
--> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<parent> |
||||||
|
<artifactId>dolphinscheduler</artifactId> |
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<version>1.3.4-SNAPSHOT</version> |
||||||
|
</parent> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
|
||||||
|
<groupId>org.apache.dolphinscheduler</groupId> |
||||||
|
<artifactId>dolphinscheduler-alert-plugin</artifactId> |
||||||
|
<packaging>pom</packaging> |
||||||
|
|
||||||
|
<modules> |
||||||
|
<module>dolphinscheduler-alert-email</module> |
||||||
|
<module>dolphinscheduler-alert-wechat</module> |
||||||
|
<module>dolphinscheduler-alert-dingtalk</module> |
||||||
|
<module>dolphinscheduler-alert-script</module> |
||||||
|
<module>dolphinscheduler-alert-http</module> |
||||||
|
</modules> |
||||||
|
|
||||||
|
|
||||||
|
</project> |
@ -1,55 +1,55 @@ |
|||||||
/* |
///*
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
// * Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
// * contributor license agreements. See the NOTICE file distributed with
|
||||||
* this work for additional information regarding copyright ownership. |
// * this work for additional information regarding copyright ownership.
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
// * The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
* (the "License"); you may not use this file except in compliance with |
// * (the "License"); you may not use this file except in compliance with
|
||||||
* the License. You may obtain a copy of the License at |
// * the License. You may obtain a copy of the License at
|
||||||
* |
// *
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* |
// *
|
||||||
* Unless required by applicable law or agreed to in writing, software |
// * Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and |
// * See the License for the specific language governing permissions and
|
||||||
* limitations under the License. |
// * limitations under the License.
|
||||||
*/ |
// */
|
||||||
package org.apache.dolphinscheduler.alert.manager; |
//package org.apache.dolphinscheduler.alert.manager;
|
||||||
|
//
|
||||||
import org.apache.dolphinscheduler.alert.utils.MailUtils; |
//import org.apache.dolphinscheduler.alert.utils.MailUtils;
|
||||||
|
//
|
||||||
import java.util.List; |
//import java.util.List;
|
||||||
import java.util.Map; |
//import java.util.Map;
|
||||||
|
//
|
||||||
/** |
///**
|
||||||
* email send manager |
// * email send manager
|
||||||
*/ |
// */
|
||||||
public class EmailManager { |
//public class EmailManager {
|
||||||
/** |
// /**
|
||||||
* email send |
// * email send
|
||||||
* @param receiversList the receiver list |
// * @param receiversList the receiver list
|
||||||
* @param receiversCcList the cc List |
// * @param receiversCcList the cc List
|
||||||
* @param title the title |
// * @param title the title
|
||||||
* @param content the content |
// * @param content the content
|
||||||
* @param showType the showType |
// * @param showType the showType
|
||||||
* @return the send result |
// * @return the send result
|
||||||
*/ |
// */
|
||||||
public Map<String,Object> send(List<String> receiversList,List<String> receiversCcList,String title,String content,String showType){ |
// public Map<String,Object> send(List<String> receiversList,List<String> receiversCcList,String title,String content,String showType){
|
||||||
|
//
|
||||||
return MailUtils.sendMails(receiversList, receiversCcList, title, content, showType); |
// return MailUtils.sendMails(receiversList, receiversCcList, title, content, showType);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
/** |
// /**
|
||||||
* msg send |
// * msg send
|
||||||
* @param receiversList the receiver list |
// * @param receiversList the receiver list
|
||||||
* @param title the title |
// * @param title the title
|
||||||
* @param content the content |
// * @param content the content
|
||||||
* @param showType the showType |
// * @param showType the showType
|
||||||
* @return the send result |
// * @return the send result
|
||||||
*/ |
// */
|
||||||
public Map<String,Object> send(List<String> receiversList,String title,String content,String showType){ |
// public Map<String,Object> send(List<String> receiversList,String title,String content,String showType){
|
||||||
|
//
|
||||||
return MailUtils.sendMails(receiversList,title, content, showType); |
// return MailUtils.sendMails(receiversList,title, content, showType);
|
||||||
} |
// }
|
||||||
|
//
|
||||||
} |
//}
|
||||||
|
@ -1,59 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.apache.dolphinscheduler.alert.manager; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.alert.utils.Constants; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.EnterpriseWeChatUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.AlertInfo; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* Enterprise WeChat Manager |
|
||||||
*/ |
|
||||||
public class EnterpriseWeChatManager { |
|
||||||
private static final Logger logger = LoggerFactory.getLogger(EnterpriseWeChatManager.class); |
|
||||||
/** |
|
||||||
* Enterprise We Chat send |
|
||||||
* @param alertInfo the alert info |
|
||||||
* @param token the token |
|
||||||
* @return the send result |
|
||||||
*/ |
|
||||||
public Map<String,Object> send(AlertInfo alertInfo, String token){ |
|
||||||
Map<String,Object> retMap = new HashMap<>(); |
|
||||||
retMap.put(Constants.STATUS, false); |
|
||||||
String agentId = EnterpriseWeChatUtils.ENTERPRISE_WE_CHAT_AGENT_ID; |
|
||||||
String users = EnterpriseWeChatUtils.ENTERPRISE_WE_CHAT_USERS; |
|
||||||
List<String> userList = Arrays.asList(users.split(",")); |
|
||||||
logger.info("send message {}", alertInfo.getAlertData().getTitle()); |
|
||||||
String msg = EnterpriseWeChatUtils.makeUserSendMsg(userList, agentId,EnterpriseWeChatUtils.markdownByAlert(alertInfo.getAlertData())); |
|
||||||
try { |
|
||||||
EnterpriseWeChatUtils.sendEnterpriseWeChat(Constants.UTF_8, msg, token); |
|
||||||
} catch (IOException e) { |
|
||||||
logger.error(e.getMessage(),e); |
|
||||||
} |
|
||||||
retMap.put(Constants.STATUS, true); |
|
||||||
return retMap; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.dao.DaoFactory; |
||||||
|
import org.apache.dolphinscheduler.dao.PluginDao; |
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
|
||||||
|
public abstract class AbstractDolphinPluginManager { |
||||||
|
|
||||||
|
protected PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class); |
||||||
|
|
||||||
|
public abstract void installPlugin(DolphinSchedulerPlugin dolphinSchedulerPlugin); |
||||||
|
} |
@ -0,0 +1,99 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import static java.lang.String.format; |
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.common.enums.PluginType; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.PluginDefine; |
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannelFactory; |
||||||
|
import org.apache.dolphinscheduler.spi.classloader.ThreadContextClassLoader; |
||||||
|
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||||
|
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* load the configured alert plugin and manager them |
||||||
|
*/ |
||||||
|
public class AlertPluginManager extends AbstractDolphinPluginManager { |
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AlertPluginManager.class); |
||||||
|
|
||||||
|
private final Map<String, AlertChannelFactory> alertChannelFactoryMap = new ConcurrentHashMap<>(); |
||||||
|
private final Map<String, AlertChannel> alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
|
||||||
|
public void addAlertChannelFactory(AlertChannelFactory alertChannelFactory) { |
||||||
|
requireNonNull(alertChannelFactory, "alertChannelFactory is null"); |
||||||
|
|
||||||
|
if (alertChannelFactoryMap.putIfAbsent(alertChannelFactory.getName(), alertChannelFactory) != null) { |
||||||
|
throw new IllegalArgumentException(format("Alert Plugin '{}' is already registered", alertChannelFactory.getName())); |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
loadAlertChannel(alertChannelFactory.getName()); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new IllegalArgumentException(format("Alert Plugin '{}' is can not load .", alertChannelFactory.getName())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void loadAlertChannel(String name) { |
||||||
|
requireNonNull(name, "name is null"); |
||||||
|
|
||||||
|
AlertChannelFactory alertChannelFactory = alertChannelFactoryMap.get(name); |
||||||
|
checkState(alertChannelFactory != null, "Alert Plugin {} is not registered", name); |
||||||
|
|
||||||
|
try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(alertChannelFactory.getClass().getClassLoader())) { |
||||||
|
AlertChannel alertChannel = alertChannelFactory.create(); |
||||||
|
this.alertChannelMap.put(name, alertChannel); |
||||||
|
} |
||||||
|
|
||||||
|
logger.info("-- Loaded Alert Plugin {} --", name); |
||||||
|
} |
||||||
|
|
||||||
|
public Map<String, AlertChannelFactory> getAlertChannelFactoryMap() { |
||||||
|
return alertChannelFactoryMap; |
||||||
|
} |
||||||
|
|
||||||
|
public Map<String, AlertChannel> getAlertChannelMap() { |
||||||
|
return alertChannelMap; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void installPlugin(DolphinSchedulerPlugin dolphinSchedulerPlugin) { |
||||||
|
for (AlertChannelFactory alertChannelFactory : dolphinSchedulerPlugin.getAlertChannelFactorys()) { |
||||||
|
logger.info("Registering Alert Plugin '{}'", alertChannelFactory.getName()); |
||||||
|
this.addAlertChannelFactory(alertChannelFactory); |
||||||
|
List<PluginParams> params = alertChannelFactory.getParams(); |
||||||
|
String nameEn = alertChannelFactory.getName(); |
||||||
|
String paramsJson = PluginParamsTransfer.transferParamsToJson(params); |
||||||
|
|
||||||
|
PluginDefine pluginDefine = new PluginDefine(nameEn, PluginType.ALERT.getDesc(), paramsJson); |
||||||
|
pluginDao.addOrUpdatePluginDefine(pluginDefine); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.net.URL; |
||||||
|
import java.net.URLClassLoader; |
||||||
|
import java.util.Enumeration; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
import com.google.common.collect.Iterables; |
||||||
|
|
||||||
|
class DolphinPluginClassLoader |
||||||
|
extends URLClassLoader { |
||||||
|
private static final ClassLoader PLATFORM_CLASS_LOADER = findPlatformClassLoader(); |
||||||
|
|
||||||
|
private final ClassLoader spiClassLoader; |
||||||
|
private final List<String> spiPackages; |
||||||
|
private final List<String> spiResources; |
||||||
|
|
||||||
|
public DolphinPluginClassLoader( |
||||||
|
List<URL> urls, |
||||||
|
ClassLoader spiClassLoader, |
||||||
|
Iterable<String> spiPackages) { |
||||||
|
this(urls, |
||||||
|
spiClassLoader, |
||||||
|
spiPackages, |
||||||
|
Iterables.transform(spiPackages, DolphinPluginClassLoader::classNameToResource)); |
||||||
|
} |
||||||
|
|
||||||
|
private DolphinPluginClassLoader( |
||||||
|
List<URL> urls, |
||||||
|
ClassLoader spiClassLoader, |
||||||
|
Iterable<String> spiPackages, |
||||||
|
Iterable<String> spiResources) { |
||||||
|
// plugins should not have access to the system (application) class loader
|
||||||
|
super(urls.toArray(new URL[urls.size()]), PLATFORM_CLASS_LOADER); |
||||||
|
this.spiClassLoader = requireNonNull(spiClassLoader, "spiClassLoader is null"); |
||||||
|
this.spiPackages = ImmutableList.copyOf(spiPackages); |
||||||
|
this.spiResources = ImmutableList.copyOf(spiResources); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected Class<?> loadClass(String name, boolean resolve) |
||||||
|
throws ClassNotFoundException { |
||||||
|
// grab the magic lock
|
||||||
|
synchronized (getClassLoadingLock(name)) { |
||||||
|
// Check if class is in the loaded classes cache
|
||||||
|
Class<?> cachedClass = findLoadedClass(name); |
||||||
|
if (cachedClass != null) { |
||||||
|
return resolveClass(cachedClass, resolve); |
||||||
|
} |
||||||
|
|
||||||
|
// If this is an SPI class, only check SPI class loader
|
||||||
|
if (isSpiClass(name)) { |
||||||
|
return resolveClass(spiClassLoader.loadClass(name), resolve); |
||||||
|
} |
||||||
|
|
||||||
|
// Look for class locally
|
||||||
|
return super.loadClass(name, resolve); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private Class<?> resolveClass(Class<?> clazz, boolean resolve) { |
||||||
|
if (resolve) { |
||||||
|
resolveClass(clazz); |
||||||
|
} |
||||||
|
return clazz; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public URL getResource(String name) { |
||||||
|
// If this is an SPI resource, only check SPI class loader
|
||||||
|
if (isSpiResource(name)) { |
||||||
|
return spiClassLoader.getResource(name); |
||||||
|
} |
||||||
|
|
||||||
|
// Look for resource locally
|
||||||
|
return super.getResource(name); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Enumeration<URL> getResources(String name) |
||||||
|
throws IOException { |
||||||
|
// If this is an SPI resource, use SPI resources
|
||||||
|
if (isSpiClass(name)) { |
||||||
|
return spiClassLoader.getResources(name); |
||||||
|
} |
||||||
|
|
||||||
|
// Use local resources
|
||||||
|
return super.getResources(name); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isSpiClass(String name) { |
||||||
|
return spiPackages.stream().anyMatch(name::startsWith); |
||||||
|
} |
||||||
|
|
||||||
|
private boolean isSpiResource(String name) { |
||||||
|
return spiResources.stream().anyMatch(name::startsWith); |
||||||
|
} |
||||||
|
|
||||||
|
private static String classNameToResource(String className) { |
||||||
|
return className.replace('.', '/'); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("JavaReflectionMemberAccess") |
||||||
|
private static ClassLoader findPlatformClassLoader() { |
||||||
|
try { |
||||||
|
// use platform class loader on Java 9
|
||||||
|
Method method = ClassLoader.class.getMethod("getPlatformClassLoader"); |
||||||
|
return (ClassLoader) method.invoke(null); |
||||||
|
} catch (NoSuchMethodException ignored) { |
||||||
|
// use null class loader on Java 8
|
||||||
|
return null; |
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) { |
||||||
|
throw new AssertionError(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8; |
||||||
|
import static java.nio.file.Files.createDirectories; |
||||||
|
import static java.nio.file.Files.walkFileTree; |
||||||
|
|
||||||
|
import static com.google.common.io.ByteStreams.toByteArray; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.FileOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.io.OutputStreamWriter; |
||||||
|
import java.io.UncheckedIOException; |
||||||
|
import java.io.Writer; |
||||||
|
import java.nio.file.FileVisitResult; |
||||||
|
import java.nio.file.Path; |
||||||
|
import java.nio.file.SimpleFileVisitor; |
||||||
|
import java.nio.file.attribute.BasicFileAttributes; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader; |
||||||
|
import org.sonatype.aether.artifact.Artifact; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
import com.google.common.collect.ImmutableSet; |
||||||
|
|
||||||
|
/** |
||||||
|
* The role of this class is to load the plugin class during development |
||||||
|
*/ |
||||||
|
final class DolphinPluginDiscovery { |
||||||
|
private static final String JAVA_CLASS_FILE_SUFFIX = ".class"; |
||||||
|
private static final String PLUGIN_SERVICES_FILE = "META-INF/services/" + DolphinSchedulerPlugin.class.getName(); |
||||||
|
|
||||||
|
private DolphinPluginDiscovery() { |
||||||
|
} |
||||||
|
|
||||||
|
public static Set<String> discoverPluginsFromArtifact(Artifact artifact, ClassLoader classLoader) |
||||||
|
throws IOException { |
||||||
|
if (!artifact.getExtension().equals("dolphinscheduler-plugin")) { |
||||||
|
throw new RuntimeException("Unexpected extension for main artifact: " + artifact); |
||||||
|
} |
||||||
|
|
||||||
|
File file = artifact.getFile(); |
||||||
|
if (!file.getPath().endsWith("/target/classes")) { |
||||||
|
throw new RuntimeException("Unexpected file for main artifact: " + file); |
||||||
|
} |
||||||
|
if (!file.isDirectory()) { |
||||||
|
throw new RuntimeException("Main artifact file is not a directory: " + file); |
||||||
|
} |
||||||
|
|
||||||
|
if (new File(file, PLUGIN_SERVICES_FILE).exists()) { |
||||||
|
return ImmutableSet.of(); |
||||||
|
} |
||||||
|
|
||||||
|
return listClasses(file.toPath()).stream() |
||||||
|
.filter(name -> classInterfaces(name, classLoader).contains(DolphinSchedulerPlugin.class.getName())) |
||||||
|
.collect(Collectors.toSet()); |
||||||
|
} |
||||||
|
|
||||||
|
public static void writePluginServices(Iterable<String> plugins, File root) |
||||||
|
throws IOException { |
||||||
|
Path path = root.toPath().resolve(PLUGIN_SERVICES_FILE); |
||||||
|
createDirectories(path.getParent()); |
||||||
|
try (Writer out = new OutputStreamWriter(new FileOutputStream(path.toFile()), UTF_8)) { |
||||||
|
for (String plugin : plugins) { |
||||||
|
out.write(plugin + "\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static List<String> listClasses(Path base) |
||||||
|
throws IOException { |
||||||
|
ImmutableList.Builder<String> list = ImmutableList.builder(); |
||||||
|
walkFileTree(base, new SimpleFileVisitor<Path>() { |
||||||
|
@Override |
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) { |
||||||
|
if (file.getFileName().toString().endsWith(JAVA_CLASS_FILE_SUFFIX)) { |
||||||
|
String name = file.subpath(base.getNameCount(), file.getNameCount()).toString(); |
||||||
|
list.add(javaName(name.substring(0, name.length() - JAVA_CLASS_FILE_SUFFIX.length()))); |
||||||
|
} |
||||||
|
return FileVisitResult.CONTINUE; |
||||||
|
} |
||||||
|
}); |
||||||
|
return list.build(); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<String> classInterfaces(String name, ClassLoader classLoader) { |
||||||
|
ImmutableList.Builder<String> list = ImmutableList.builder(); |
||||||
|
ClassReader reader = readClass(name, classLoader); |
||||||
|
for (String binaryName : reader.getInterfaces()) { |
||||||
|
list.add(javaName(binaryName)); |
||||||
|
} |
||||||
|
if (reader.getSuperName() != null) { |
||||||
|
list.addAll(classInterfaces(javaName(reader.getSuperName()), classLoader)); |
||||||
|
} |
||||||
|
return list.build(); |
||||||
|
} |
||||||
|
|
||||||
|
private static ClassReader readClass(String name, ClassLoader classLoader) { |
||||||
|
try (InputStream in = classLoader.getResourceAsStream(binaryName(name) + JAVA_CLASS_FILE_SUFFIX)) { |
||||||
|
if (in == null) { |
||||||
|
throw new RuntimeException("Failed to read class: " + name); |
||||||
|
} |
||||||
|
return new ClassReader(toByteArray(in)); |
||||||
|
} catch (IOException e) { |
||||||
|
throw new UncheckedIOException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static String binaryName(String javaName) { |
||||||
|
return javaName.replace('.', '/'); |
||||||
|
} |
||||||
|
|
||||||
|
private static String javaName(String binaryName) { |
||||||
|
return binaryName.replace('/', '.'); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,194 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import static java.lang.String.format; |
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkState; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||||
|
import org.apache.dolphinscheduler.spi.classloader.ThreadContextClassLoader; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.io.IOException; |
||||||
|
import java.net.URL; |
||||||
|
import java.net.URLClassLoader; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.ServiceLoader; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.sonatype.aether.artifact.Artifact; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
import com.google.common.collect.Ordering; |
||||||
|
|
||||||
|
import io.airlift.resolver.ArtifactResolver; |
||||||
|
|
||||||
|
/** |
||||||
|
* Plugin Loader |
||||||
|
* Load Plugin from pom when development and run server in IDE |
||||||
|
* Load Plugin from the plugin directory when running on the server |
||||||
|
*/ |
||||||
|
public class DolphinPluginLoader { |
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DolphinPluginLoader.class); |
||||||
|
|
||||||
|
/** |
||||||
|
* All third-party jar packages used in the classes which in spi package need to be add |
||||||
|
*/ |
||||||
|
private static final ImmutableList<String> DOLPHIN_SPI_PACKAGES = ImmutableList.<String>builder() |
||||||
|
.add("org.apache.dolphinscheduler.spi.") |
||||||
|
.add("com.fasterxml.jackson.") |
||||||
|
.build(); |
||||||
|
|
||||||
|
private final File installedPluginsDir; |
||||||
|
private final List<String> configPlugins; |
||||||
|
private ArtifactResolver resolver = null; |
||||||
|
private final List<AbstractDolphinPluginManager> dolphinPluginManagerList; |
||||||
|
|
||||||
|
public DolphinPluginLoader(DolphinPluginManagerConfig config, List<AbstractDolphinPluginManager> dolphinPluginManagerList) { |
||||||
|
installedPluginsDir = config.getInstalledPluginsDir(); |
||||||
|
if (config.getPlugins() == null) { |
||||||
|
this.configPlugins = ImmutableList.of(); |
||||||
|
} else { |
||||||
|
this.configPlugins = ImmutableList.copyOf(config.getPlugins()); |
||||||
|
} |
||||||
|
|
||||||
|
this.dolphinPluginManagerList = requireNonNull(dolphinPluginManagerList, "dolphinPluginManagerList is null"); |
||||||
|
if (configPlugins != null && configPlugins.size() > 0) { |
||||||
|
this.resolver = new ArtifactResolver(config.getMavenLocalRepository(), config.getMavenRemoteRepository()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void loadPlugins() |
||||||
|
throws Exception { |
||||||
|
for (File file : listPluginDirs(installedPluginsDir)) { |
||||||
|
if (file.isDirectory()) { |
||||||
|
loadPlugin(file.getAbsolutePath()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (String plugin : configPlugins) { |
||||||
|
loadPlugin(plugin); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void loadPlugin(String plugin) |
||||||
|
throws Exception { |
||||||
|
logger.info("-- Loading Alert plugin {} --", plugin); |
||||||
|
URLClassLoader pluginClassLoader = buildPluginClassLoader(plugin); |
||||||
|
try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(pluginClassLoader)) { |
||||||
|
loadPlugin(pluginClassLoader); |
||||||
|
} |
||||||
|
logger.info("-- Finished loading Alert plugin {} --", plugin); |
||||||
|
} |
||||||
|
|
||||||
|
private void loadPlugin(URLClassLoader pluginClassLoader) { |
||||||
|
ServiceLoader<DolphinSchedulerPlugin> serviceLoader = ServiceLoader.load(DolphinSchedulerPlugin.class, pluginClassLoader); |
||||||
|
List<DolphinSchedulerPlugin> plugins = ImmutableList.copyOf(serviceLoader); |
||||||
|
checkState(!plugins.isEmpty(), "No service providers the plugin {}", DolphinSchedulerPlugin.class.getName()); |
||||||
|
for (DolphinSchedulerPlugin plugin : plugins) { |
||||||
|
logger.info("Installing {}", plugin.getClass().getName()); |
||||||
|
for (AbstractDolphinPluginManager dolphinPluginManager : dolphinPluginManagerList) { |
||||||
|
dolphinPluginManager.installPlugin(plugin); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private URLClassLoader buildPluginClassLoader(String plugin) |
||||||
|
throws Exception { |
||||||
|
File file = new File(plugin); |
||||||
|
|
||||||
|
if (!file.isDirectory() && (file.getName().equals("pom.xml") || file.getName().endsWith(".pom"))) { |
||||||
|
return buildPluginClassLoaderFromPom(file); |
||||||
|
} |
||||||
|
if (file.isDirectory()) { |
||||||
|
return buildPluginClassLoaderFromDirectory(file); |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException(format("plugin must be a pom file or directory {} .", plugin)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private URLClassLoader buildPluginClassLoaderFromPom(File pomFile) |
||||||
|
throws Exception { |
||||||
|
List<Artifact> artifacts = resolver.resolvePom(pomFile); |
||||||
|
URLClassLoader classLoader = createClassLoader(artifacts, pomFile.getPath()); |
||||||
|
|
||||||
|
Artifact artifact = artifacts.get(0); |
||||||
|
Set<String> plugins = DolphinPluginDiscovery.discoverPluginsFromArtifact(artifact, classLoader); |
||||||
|
if (!plugins.isEmpty()) { |
||||||
|
DolphinPluginDiscovery.writePluginServices(plugins, artifact.getFile()); |
||||||
|
} |
||||||
|
|
||||||
|
return classLoader; |
||||||
|
} |
||||||
|
|
||||||
|
private URLClassLoader buildPluginClassLoaderFromDirectory(File dir) |
||||||
|
throws Exception { |
||||||
|
logger.info("Classpath for {}:", dir.getName()); |
||||||
|
List<URL> urls = new ArrayList<>(); |
||||||
|
for (File file : listPluginDirs(dir)) { |
||||||
|
logger.info(" {}", file); |
||||||
|
urls.add(file.toURI().toURL()); |
||||||
|
} |
||||||
|
return createClassLoader(urls); |
||||||
|
} |
||||||
|
|
||||||
|
private URLClassLoader createClassLoader(List<Artifact> artifacts, String name) |
||||||
|
throws IOException { |
||||||
|
logger.info("Classpath for {}:", name); |
||||||
|
List<URL> urls = new ArrayList<>(); |
||||||
|
for (Artifact artifact : sortArtifacts(artifacts)) { |
||||||
|
if (artifact.getFile() == null) { |
||||||
|
throw new RuntimeException("Could not resolve artifact: " + artifact); |
||||||
|
} |
||||||
|
File file = artifact.getFile().getCanonicalFile(); |
||||||
|
logger.info(" {}", file); |
||||||
|
urls.add(file.toURI().toURL()); |
||||||
|
} |
||||||
|
return createClassLoader(urls); |
||||||
|
} |
||||||
|
|
||||||
|
private URLClassLoader createClassLoader(List<URL> urls) { |
||||||
|
ClassLoader parent = getClass().getClassLoader(); |
||||||
|
return new DolphinPluginClassLoader(urls, parent, DOLPHIN_SPI_PACKAGES); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<File> listPluginDirs(File installedPluginsDir) { |
||||||
|
if (installedPluginsDir != null && installedPluginsDir.isDirectory()) { |
||||||
|
File[] files = installedPluginsDir.listFiles(); |
||||||
|
if (files != null) { |
||||||
|
Arrays.sort(files); |
||||||
|
return ImmutableList.copyOf(files); |
||||||
|
} |
||||||
|
} |
||||||
|
return ImmutableList.of(); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<Artifact> sortArtifacts(List<Artifact> artifacts) { |
||||||
|
List<Artifact> list = new ArrayList<>(artifacts); |
||||||
|
Collections.sort(list, Ordering.natural().nullsLast().onResultOf(Artifact::getFile)); |
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import static java.lang.String.format; |
||||||
|
import static java.util.Objects.requireNonNull; |
||||||
|
|
||||||
|
import java.io.File; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import com.google.common.base.Splitter; |
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* Dolphin Scheduler Plugin Manager Config |
||||||
|
*/ |
||||||
|
public class DolphinPluginManagerConfig { |
||||||
|
|
||||||
|
/** |
||||||
|
* The dir of the Alert Plugin in. |
||||||
|
* When AlertServer is running on the server, it will load the Alert Plugin from this directory. |
||||||
|
*/ |
||||||
|
private File installedPluginsDir; |
||||||
|
|
||||||
|
/** |
||||||
|
* The plugin should be load. |
||||||
|
* The installedPluginsDir is empty when we development and run server in IDEA. Then we can config which plugin should be load by param name alert.plugin.binding in the alert.properties file |
||||||
|
*/ |
||||||
|
private List<String> plugins; |
||||||
|
|
||||||
|
/** |
||||||
|
* Development, When AlertServer is running on IDE, AlertPluginLoad can load Alert Plugin from local Repository. |
||||||
|
*/ |
||||||
|
private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; |
||||||
|
private List<String> mavenRemoteRepository = ImmutableList.of("http://repo1.maven.org/maven2/"); |
||||||
|
|
||||||
|
public File getInstalledPluginsDir() { |
||||||
|
return installedPluginsDir; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param pluginDir |
||||||
|
*/ |
||||||
|
public DolphinPluginManagerConfig setInstalledPluginsDir(String pluginDir) { |
||||||
|
requireNonNull(pluginDir, "pluginDir can not be null"); |
||||||
|
File pluginDirFile = new File(pluginDir); |
||||||
|
if (!pluginDirFile.exists()) { |
||||||
|
throw new IllegalArgumentException(format("plugin dir not exists ! {}", pluginDirFile.getPath())); |
||||||
|
} |
||||||
|
this.installedPluginsDir = pluginDirFile; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getPlugins() { |
||||||
|
return plugins; |
||||||
|
} |
||||||
|
|
||||||
|
public DolphinPluginManagerConfig setPlugins(List<String> plugins) { |
||||||
|
this.plugins = plugins; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* When development and run server in IDE, this method can set plugins in alert.properties . |
||||||
|
* Then when you start AlertServer in IDE, the plugin can be load. |
||||||
|
* eg: |
||||||
|
* file: alert.properties |
||||||
|
* alert.plugin=\ |
||||||
|
* ../dolphinscheduler-alert-plugin/dolphinscheduler-alert-email/pom.xml, \ |
||||||
|
* ../dolphinscheduler-alert-plugin/dolphinscheduler-alert-wechat/pom.xml |
||||||
|
* |
||||||
|
* @param plugins |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public DolphinPluginManagerConfig setPlugins(String plugins) { |
||||||
|
if (plugins == null) { |
||||||
|
this.plugins = null; |
||||||
|
} else { |
||||||
|
this.plugins = ImmutableList.copyOf(Splitter.on(',').omitEmptyStrings().trimResults().split(plugins)); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public String getMavenLocalRepository() { |
||||||
|
return mavenLocalRepository; |
||||||
|
} |
||||||
|
|
||||||
|
public DolphinPluginManagerConfig setMavenLocalRepository(String mavenLocalRepository) { |
||||||
|
this.mavenLocalRepository = mavenLocalRepository; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public List<String> getMavenRemoteRepository() { |
||||||
|
return mavenRemoteRepository; |
||||||
|
} |
||||||
|
|
||||||
|
public DolphinPluginManagerConfig setMavenRemoteRepository(List<String> mavenRemoteRepository) { |
||||||
|
this.mavenRemoteRepository = mavenRemoteRepository; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public DolphinPluginManagerConfig setMavenRemoteRepository(String mavenRemoteRepository) { |
||||||
|
this.mavenRemoteRepository = ImmutableList.copyOf(Splitter.on(',').omitEmptyStrings().trimResults().split(mavenRemoteRepository)); |
||||||
|
return this; |
||||||
|
} |
||||||
|
} |
@ -1,147 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.apache.dolphinscheduler.alert.plugin; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.alert.manager.DingTalkManager; |
|
||||||
import org.apache.dolphinscheduler.alert.manager.EmailManager; |
|
||||||
import org.apache.dolphinscheduler.alert.manager.EnterpriseWeChatManager; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.Constants; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.DingTalkUtils; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.EnterpriseWeChatUtils; |
|
||||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
|
||||||
import org.apache.dolphinscheduler.common.utils.StringUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.api.AlertPlugin; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.AlertData; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.AlertInfo; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.PluginName; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* EmailAlertPlugin |
|
||||||
* <p> |
|
||||||
* This plugin is a default plugin, and mix up email and enterprise wechat, because adapt with former alert behavior |
|
||||||
*/ |
|
||||||
public class EmailAlertPlugin implements AlertPlugin { |
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(EmailAlertPlugin.class); |
|
||||||
|
|
||||||
private PluginName pluginName; |
|
||||||
|
|
||||||
private static final EmailManager emailManager = new EmailManager(); |
|
||||||
private static final EnterpriseWeChatManager weChatManager = new EnterpriseWeChatManager(); |
|
||||||
private static final DingTalkManager dingTalkManager = new DingTalkManager(); |
|
||||||
|
|
||||||
public EmailAlertPlugin() { |
|
||||||
this.pluginName = new PluginName(); |
|
||||||
this.pluginName.setEnglish(Constants.PLUGIN_DEFAULT_EMAIL_EN); |
|
||||||
this.pluginName.setChinese(Constants.PLUGIN_DEFAULT_EMAIL_CH); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String getId() { |
|
||||||
return Constants.PLUGIN_DEFAULT_EMAIL_ID; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public PluginName getName() { |
|
||||||
return pluginName; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
public Map<String, Object> process(AlertInfo info) { |
|
||||||
Map<String, Object> retMaps = new HashMap<>(); |
|
||||||
|
|
||||||
AlertData alert = info.getAlertData(); |
|
||||||
|
|
||||||
List<String> receiversList = (List<String>) info.getProp(Constants.PLUGIN_DEFAULT_EMAIL_RECEIVERS); |
|
||||||
|
|
||||||
// receiving group list
|
|
||||||
// custom receiver
|
|
||||||
String receivers = alert.getReceivers(); |
|
||||||
if (StringUtils.isNotEmpty(receivers)) { |
|
||||||
String[] splits = receivers.split(","); |
|
||||||
receiversList.addAll(Arrays.asList(splits)); |
|
||||||
} |
|
||||||
|
|
||||||
List<String> receiversCcList = new ArrayList<>(); |
|
||||||
// Custom Copier
|
|
||||||
String receiversCc = alert.getReceiversCc(); |
|
||||||
if (StringUtils.isNotEmpty(receiversCc)) { |
|
||||||
String[] splits = receiversCc.split(","); |
|
||||||
receiversCcList.addAll(Arrays.asList(splits)); |
|
||||||
} |
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(receiversList) && CollectionUtils.isEmpty(receiversCcList)) { |
|
||||||
logger.warn("alert send error : At least one receiver address required"); |
|
||||||
retMaps.put(Constants.STATUS, "false"); |
|
||||||
retMaps.put(Constants.MESSAGE, "execution failure,At least one receiver address required."); |
|
||||||
return retMaps; |
|
||||||
} |
|
||||||
|
|
||||||
retMaps = emailManager.send(receiversList, receiversCcList, alert.getTitle(), alert.getContent(), |
|
||||||
alert.getShowType()); |
|
||||||
|
|
||||||
//send flag
|
|
||||||
boolean flag = false; |
|
||||||
|
|
||||||
if (retMaps == null) { |
|
||||||
retMaps = new HashMap<>(); |
|
||||||
retMaps.put(Constants.MESSAGE, "alert send error."); |
|
||||||
retMaps.put(Constants.STATUS, "false"); |
|
||||||
logger.info("alert send error : {}", retMaps.get(Constants.MESSAGE)); |
|
||||||
return retMaps; |
|
||||||
} |
|
||||||
|
|
||||||
flag = Boolean.parseBoolean(String.valueOf(retMaps.get(Constants.STATUS))); |
|
||||||
|
|
||||||
if (flag) { |
|
||||||
logger.info("alert send success"); |
|
||||||
retMaps.put(Constants.MESSAGE, "email send success."); |
|
||||||
if (EnterpriseWeChatUtils.isEnable()) { |
|
||||||
logger.info("Enterprise WeChat is enable!"); |
|
||||||
try { |
|
||||||
String token = EnterpriseWeChatUtils.getToken(); |
|
||||||
weChatManager.send(info, token); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error(e.getMessage(), e); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (DingTalkUtils.IS_ENABLE_DING_TALK) { |
|
||||||
logger.info("Ding Talk is enable."); |
|
||||||
dingTalkManager.send(info); |
|
||||||
} |
|
||||||
|
|
||||||
} else { |
|
||||||
retMaps.put(Constants.MESSAGE, "alert send error."); |
|
||||||
logger.info("alert send error : {}", retMaps.get(Constants.MESSAGE)); |
|
||||||
} |
|
||||||
|
|
||||||
return retMaps; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.processor; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager; |
||||||
|
import org.apache.dolphinscheduler.alert.runner.AlertSender; |
||||||
|
import org.apache.dolphinscheduler.common.utils.Preconditions; |
||||||
|
import org.apache.dolphinscheduler.dao.AlertDao; |
||||||
|
import org.apache.dolphinscheduler.dao.PluginDao; |
||||||
|
import org.apache.dolphinscheduler.remote.command.Command; |
||||||
|
import org.apache.dolphinscheduler.remote.command.CommandType; |
||||||
|
import org.apache.dolphinscheduler.remote.command.alert.AlertSendRequestCommand; |
||||||
|
import org.apache.dolphinscheduler.remote.command.alert.AlertSendResponseCommand; |
||||||
|
import org.apache.dolphinscheduler.remote.processor.NettyRequestProcessor; |
||||||
|
import org.apache.dolphinscheduler.remote.utils.JsonSerializer; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import io.netty.channel.Channel; |
||||||
|
|
||||||
|
/** |
||||||
|
* alert request processor |
||||||
|
*/ |
||||||
|
public class AlertRequestProcessor implements NettyRequestProcessor { |
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(AlertRequestProcessor.class); |
||||||
|
private AlertDao alertDao; |
||||||
|
private PluginDao pluginDao; |
||||||
|
private AlertPluginManager alertPluginManager; |
||||||
|
|
||||||
|
public AlertRequestProcessor(AlertDao alertDao, AlertPluginManager alertPluginManager, PluginDao pluginDao) { |
||||||
|
this.alertDao = alertDao; |
||||||
|
this.pluginDao = pluginDao; |
||||||
|
this.alertPluginManager = alertPluginManager; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void process(Channel channel, Command command) { |
||||||
|
Preconditions.checkArgument(CommandType.ALERT_SEND_REQUEST == command.getType(), |
||||||
|
String.format("invalid command type : %s", command.getType())); |
||||||
|
|
||||||
|
AlertSendRequestCommand alertSendRequestCommand = JsonSerializer.deserialize( |
||||||
|
command.getBody(), AlertSendRequestCommand.class); |
||||||
|
logger.info("received command : {}", alertSendRequestCommand); |
||||||
|
|
||||||
|
AlertSender alertSender = new AlertSender(alertDao, alertPluginManager, pluginDao); |
||||||
|
AlertSendResponseCommand alertSendResponseCommand = alertSender.syncHandler(alertSendRequestCommand.getGroupId(), alertSendRequestCommand.getTitle(), alertSendRequestCommand.getContent()); |
||||||
|
channel.writeAndFlush(alertSendResponseCommand.convert2Command(command.getOpaque())); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -1,141 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.utils.*; |
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.StringUtils; |
|
||||||
import org.apache.http.HttpEntity; |
|
||||||
import org.apache.http.HttpHost; |
|
||||||
import org.apache.http.auth.AuthScope; |
|
||||||
import org.apache.http.auth.UsernamePasswordCredentials; |
|
||||||
import org.apache.http.client.CredentialsProvider; |
|
||||||
import org.apache.http.client.config.RequestConfig; |
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse; |
|
||||||
import org.apache.http.client.methods.HttpPost; |
|
||||||
import org.apache.http.entity.StringEntity; |
|
||||||
import org.apache.http.impl.client.BasicCredentialsProvider; |
|
||||||
import org.apache.http.impl.client.CloseableHttpClient; |
|
||||||
import org.apache.http.impl.client.HttpClients; |
|
||||||
import org.apache.http.util.EntityUtils; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* DingTalkUtils utils |
|
||||||
* support send msg to ding talk by robot message push function. |
|
||||||
* support PROXY setting |
|
||||||
*/ |
|
||||||
public class DingTalkUtils { |
|
||||||
public static final Logger logger = LoggerFactory.getLogger(DingTalkUtils.class); |
|
||||||
|
|
||||||
public static final boolean IS_ENABLE_DING_TALK = PropertyUtils.getBoolean(Constants.DINGTALK_ENABLE); |
|
||||||
private static final String DING_TASK_URL = PropertyUtils.getString(Constants.DINGTALK_WEBHOOK); |
|
||||||
private static final String KEYWORD = PropertyUtils.getString(Constants.DINGTALK_KEYWORD); |
|
||||||
private static final Boolean IS_ENABLE_PROXY = PropertyUtils.getBoolean(Constants.DINGTALK_PROXY_ENABLE); |
|
||||||
private static final String PROXY = PropertyUtils.getString(Constants.DINGTALK_PROXY); |
|
||||||
private static final String USER = PropertyUtils.getString(Constants.DINGTALK_USER); |
|
||||||
private static final String PASSWD = PropertyUtils.getString(Constants.DINGTALK_PASSWORD); |
|
||||||
private static final Integer PORT = PropertyUtils.getInt(Constants.DINGTALK_PORT); |
|
||||||
|
|
||||||
private DingTalkUtils() { |
|
||||||
throw new IllegalStateException(DingTalkUtils.class.getName()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* send message interface
|
|
||||||
* only support text message format now. |
|
||||||
* |
|
||||||
* @param msg message context to send |
|
||||||
* @param charset charset type |
|
||||||
* @return result of sending msg |
|
||||||
* @throws IOException the IOException |
|
||||||
*/ |
|
||||||
public static String sendDingTalkMsg(String msg, String charset) throws IOException { |
|
||||||
String msgToJson = textToJsonString(msg + "#" + KEYWORD); |
|
||||||
HttpPost httpPost = constructHttpPost(msgToJson, charset); |
|
||||||
|
|
||||||
CloseableHttpClient httpClient; |
|
||||||
if (Boolean.TRUE.equals(IS_ENABLE_PROXY)) { |
|
||||||
httpClient = getProxyClient(); |
|
||||||
RequestConfig rcf = getProxyConfig(); |
|
||||||
httpPost.setConfig(rcf); |
|
||||||
} else { |
|
||||||
httpClient = getDefaultClient(); |
|
||||||
} |
|
||||||
|
|
||||||
try { |
|
||||||
CloseableHttpResponse response = httpClient.execute(httpPost); |
|
||||||
String resp; |
|
||||||
try { |
|
||||||
HttpEntity entity = response.getEntity(); |
|
||||||
resp = EntityUtils.toString(entity, charset); |
|
||||||
EntityUtils.consume(entity); |
|
||||||
} finally { |
|
||||||
response.close(); |
|
||||||
} |
|
||||||
logger.info("Ding Talk send [{}], resp:{%s}", msg); |
|
||||||
return resp; |
|
||||||
} finally { |
|
||||||
httpClient.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static HttpPost constructHttpPost(String msg, String charset) { |
|
||||||
HttpPost post = new HttpPost(DING_TASK_URL); |
|
||||||
StringEntity entity = new StringEntity(msg, charset); |
|
||||||
post.setEntity(entity); |
|
||||||
post.addHeader("Content-Type", "application/json; charset=utf-8"); |
|
||||||
return post; |
|
||||||
} |
|
||||||
|
|
||||||
public static CloseableHttpClient getProxyClient() { |
|
||||||
HttpHost httpProxy = new HttpHost(PROXY, PORT); |
|
||||||
CredentialsProvider provider = new BasicCredentialsProvider(); |
|
||||||
provider.setCredentials(new AuthScope(httpProxy), new UsernamePasswordCredentials(USER, PASSWD)); |
|
||||||
return HttpClients.custom().setDefaultCredentialsProvider(provider).build(); |
|
||||||
} |
|
||||||
|
|
||||||
public static CloseableHttpClient getDefaultClient() { |
|
||||||
return HttpClients.createDefault(); |
|
||||||
} |
|
||||||
|
|
||||||
public static RequestConfig getProxyConfig() { |
|
||||||
HttpHost httpProxy = new HttpHost(PROXY, PORT); |
|
||||||
return RequestConfig.custom().setProxy(httpProxy).build(); |
|
||||||
} |
|
||||||
|
|
||||||
public static String textToJsonString(String text) { |
|
||||||
Map<String, Object> items = new HashMap<>(); |
|
||||||
items.put("msgtype", "text"); |
|
||||||
Map<String, String> textContent = new HashMap<>(); |
|
||||||
byte[] byt = StringUtils.getBytesUtf8(text); |
|
||||||
String txt = StringUtils.newStringUtf8(byt); |
|
||||||
textContent.put("content", txt); |
|
||||||
items.put("text", textContent); |
|
||||||
|
|
||||||
return JSONUtils.toJsonString(items); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,286 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.enums.ShowType; |
|
||||||
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
|
||||||
import org.apache.dolphinscheduler.common.utils.StringUtils; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.AlertData; |
|
||||||
|
|
||||||
import org.apache.http.HttpEntity; |
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse; |
|
||||||
import org.apache.http.client.methods.HttpGet; |
|
||||||
import org.apache.http.client.methods.HttpPost; |
|
||||||
import org.apache.http.entity.StringEntity; |
|
||||||
import org.apache.http.impl.client.CloseableHttpClient; |
|
||||||
import org.apache.http.impl.client.HttpClients; |
|
||||||
import org.apache.http.util.EntityUtils; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.LinkedHashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Set; |
|
||||||
|
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* Enterprise WeChat utils |
|
||||||
*/ |
|
||||||
public class EnterpriseWeChatUtils { |
|
||||||
|
|
||||||
public static final Logger logger = LoggerFactory.getLogger(EnterpriseWeChatUtils.class); |
|
||||||
public static final String ENTERPRISE_WE_CHAT_AGENT_ID = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_AGENT_ID); |
|
||||||
public static final String ENTERPRISE_WE_CHAT_USERS = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_USERS); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_CORP_ID = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_CORP_ID); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_SECRET = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_SECRET); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_TOKEN_URL = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_TOKEN_URL); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_TOKEN_URL_REPLACE = ENTERPRISE_WE_CHAT_TOKEN_URL == null ? null : ENTERPRISE_WE_CHAT_TOKEN_URL |
|
||||||
.replaceAll("\\{corpId}", ENTERPRISE_WE_CHAT_CORP_ID) |
|
||||||
.replaceAll("\\{secret}", ENTERPRISE_WE_CHAT_SECRET); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_PUSH_URL = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_PUSH_URL); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_TEAM_SEND_MSG = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_TEAM_SEND_MSG); |
|
||||||
private static final String ENTERPRISE_WE_CHAT_USER_SEND_MSG = PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_USER_SEND_MSG); |
|
||||||
|
|
||||||
private static final String AGENT_ID_REG_EXP = "\\{agentId}"; |
|
||||||
private static final String MSG_REG_EXP = "\\{msg}"; |
|
||||||
private static final String USER_REG_EXP = "\\{toUser}"; |
|
||||||
|
|
||||||
private EnterpriseWeChatUtils() { |
|
||||||
throw new IllegalStateException(EnterpriseWeChatUtils.class.getName()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get Enterprise WeChat is enable |
|
||||||
* |
|
||||||
* @return isEnable |
|
||||||
*/ |
|
||||||
public static boolean isEnable() { |
|
||||||
Boolean isEnable = null; |
|
||||||
try { |
|
||||||
isEnable = PropertyUtils.getBoolean(Constants.ENTERPRISE_WECHAT_ENABLE); |
|
||||||
} catch (Exception e) { |
|
||||||
logger.error(e.getMessage(), e); |
|
||||||
} |
|
||||||
if (isEnable == null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
return isEnable; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get Enterprise WeChat token info |
|
||||||
* |
|
||||||
* @return token string info |
|
||||||
* @throws IOException the IOException |
|
||||||
*/ |
|
||||||
public static String getToken() throws IOException { |
|
||||||
String resp; |
|
||||||
|
|
||||||
CloseableHttpClient httpClient = HttpClients.createDefault(); |
|
||||||
try { |
|
||||||
HttpGet httpGet = new HttpGet(ENTERPRISE_WE_CHAT_TOKEN_URL_REPLACE); |
|
||||||
CloseableHttpResponse response = httpClient.execute(httpGet); |
|
||||||
try { |
|
||||||
HttpEntity entity = response.getEntity(); |
|
||||||
resp = EntityUtils.toString(entity, Constants.UTF_8); |
|
||||||
EntityUtils.consume(entity); |
|
||||||
} finally { |
|
||||||
response.close(); |
|
||||||
} |
|
||||||
|
|
||||||
Map<String, String> map = JSONUtils.toMap(resp); |
|
||||||
return map == null ? null : map.get("access_token"); |
|
||||||
} finally { |
|
||||||
httpClient.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* make team single Enterprise WeChat message |
|
||||||
* |
|
||||||
* @param toParty the toParty |
|
||||||
* @param agentId the agentId |
|
||||||
* @param msg the msg |
|
||||||
* @return Enterprise WeChat send message |
|
||||||
*/ |
|
||||||
public static String makeTeamSendMsg(String toParty, String agentId, String msg) { |
|
||||||
return ENTERPRISE_WE_CHAT_TEAM_SEND_MSG.replaceAll("\\{toParty}", toParty) |
|
||||||
.replaceAll(AGENT_ID_REG_EXP, agentId) |
|
||||||
.replaceAll(MSG_REG_EXP, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* make team multi Enterprise WeChat message |
|
||||||
* |
|
||||||
* @param toParty the toParty |
|
||||||
* @param agentId the agentId |
|
||||||
* @param msg the msg |
|
||||||
* @return Enterprise WeChat send message |
|
||||||
*/ |
|
||||||
public static String makeTeamSendMsg(Collection<String> toParty, String agentId, String msg) { |
|
||||||
String listParty = FuncUtils.mkString(toParty, "|"); |
|
||||||
return ENTERPRISE_WE_CHAT_TEAM_SEND_MSG.replaceAll("\\{toParty}", listParty) |
|
||||||
.replaceAll(AGENT_ID_REG_EXP, agentId) |
|
||||||
.replaceAll(MSG_REG_EXP, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* make team single user message |
|
||||||
* |
|
||||||
* @param toUser the toUser |
|
||||||
* @param agentId the agentId |
|
||||||
* @param msg the msg |
|
||||||
* @return Enterprise WeChat send message |
|
||||||
*/ |
|
||||||
public static String makeUserSendMsg(String toUser, String agentId, String msg) { |
|
||||||
return ENTERPRISE_WE_CHAT_USER_SEND_MSG.replaceAll(USER_REG_EXP, toUser) |
|
||||||
.replaceAll(AGENT_ID_REG_EXP, agentId) |
|
||||||
.replaceAll(MSG_REG_EXP, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* make team multi user message |
|
||||||
* |
|
||||||
* @param toUser the toUser |
|
||||||
* @param agentId the agentId |
|
||||||
* @param msg the msg |
|
||||||
* @return Enterprise WeChat send message |
|
||||||
*/ |
|
||||||
public static String makeUserSendMsg(Collection<String> toUser, String agentId, String msg) { |
|
||||||
String listUser = FuncUtils.mkString(toUser, "|"); |
|
||||||
return ENTERPRISE_WE_CHAT_USER_SEND_MSG.replaceAll(USER_REG_EXP, listUser) |
|
||||||
.replaceAll(AGENT_ID_REG_EXP, agentId) |
|
||||||
.replaceAll(MSG_REG_EXP, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* send Enterprise WeChat |
|
||||||
* |
|
||||||
* @param charset the charset |
|
||||||
* @param data the data |
|
||||||
* @param token the token |
|
||||||
* @return Enterprise WeChat resp, demo: {"errcode":0,"errmsg":"ok","invaliduser":""} |
|
||||||
* @throws IOException the IOException |
|
||||||
*/ |
|
||||||
public static String sendEnterpriseWeChat(String charset, String data, String token) throws IOException { |
|
||||||
String enterpriseWeChatPushUrlReplace = ENTERPRISE_WE_CHAT_PUSH_URL.replaceAll("\\{token}", token); |
|
||||||
|
|
||||||
CloseableHttpClient httpClient = HttpClients.createDefault(); |
|
||||||
try { |
|
||||||
HttpPost httpPost = new HttpPost(enterpriseWeChatPushUrlReplace); |
|
||||||
httpPost.setEntity(new StringEntity(data, charset)); |
|
||||||
CloseableHttpResponse response = httpClient.execute(httpPost); |
|
||||||
String resp; |
|
||||||
try { |
|
||||||
HttpEntity entity = response.getEntity(); |
|
||||||
resp = EntityUtils.toString(entity, charset); |
|
||||||
EntityUtils.consume(entity); |
|
||||||
} finally { |
|
||||||
response.close(); |
|
||||||
} |
|
||||||
logger.info("Enterprise WeChat send [{}], param:{}, resp:{}", |
|
||||||
ENTERPRISE_WE_CHAT_PUSH_URL, data, resp); |
|
||||||
return resp; |
|
||||||
} finally { |
|
||||||
httpClient.close(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* convert table to markdown style |
|
||||||
* |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @return markdown table content |
|
||||||
*/ |
|
||||||
public static String markdownTable(String title, String content) { |
|
||||||
List<LinkedHashMap> mapItemsList = JSONUtils.toList(content, LinkedHashMap.class); |
|
||||||
StringBuilder contents = new StringBuilder(200); |
|
||||||
|
|
||||||
if (null != mapItemsList) { |
|
||||||
for (LinkedHashMap mapItems : mapItemsList) { |
|
||||||
Set<Map.Entry<String, Object>> entries = mapItems.entrySet(); |
|
||||||
Iterator<Map.Entry<String, Object>> iterator = entries.iterator(); |
|
||||||
StringBuilder t = new StringBuilder(String.format("`%s`%s", title, Constants.MARKDOWN_ENTER)); |
|
||||||
|
|
||||||
while (iterator.hasNext()) { |
|
||||||
|
|
||||||
Map.Entry<String, Object> entry = iterator.next(); |
|
||||||
t.append(Constants.MARKDOWN_QUOTE); |
|
||||||
t.append(entry.getKey()).append(":").append(entry.getValue()); |
|
||||||
t.append(Constants.MARKDOWN_ENTER); |
|
||||||
} |
|
||||||
contents.append(t); |
|
||||||
} |
|
||||||
} |
|
||||||
return contents.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* convert text to markdown style |
|
||||||
* |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @return markdown text |
|
||||||
*/ |
|
||||||
public static String markdownText(String title, String content) { |
|
||||||
if (StringUtils.isNotEmpty(content)) { |
|
||||||
List<LinkedHashMap> mapItemsList = JSONUtils.toList(content, LinkedHashMap.class); |
|
||||||
if (null != mapItemsList) { |
|
||||||
StringBuilder contents = new StringBuilder(100); |
|
||||||
contents.append(String.format("`%s`%n", title)); |
|
||||||
for (LinkedHashMap mapItems : mapItemsList) { |
|
||||||
|
|
||||||
Set<Map.Entry<String, Object>> entries = mapItems.entrySet(); |
|
||||||
Iterator<Map.Entry<String, Object>> iterator = entries.iterator(); |
|
||||||
while (iterator.hasNext()) { |
|
||||||
Map.Entry<String, Object> entry = iterator.next(); |
|
||||||
contents.append(Constants.MARKDOWN_QUOTE); |
|
||||||
contents.append(entry.getKey()).append(":").append(entry.getValue()); |
|
||||||
contents.append(Constants.MARKDOWN_ENTER); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
return contents.toString(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Determine the mardown style based on the show type of the alert |
|
||||||
* |
|
||||||
* @return the markdown alert table/text |
|
||||||
*/ |
|
||||||
public static String markdownByAlert(AlertData alert) { |
|
||||||
String result = ""; |
|
||||||
if (alert.getShowType().equals(ShowType.TABLE.getDescp())) { |
|
||||||
result = markdownTable(alert.getTitle(), alert.getContent()); |
|
||||||
} else if (alert.getShowType().equals(ShowType.TEXT.getDescp())) { |
|
||||||
result = markdownText(alert.getTitle(), alert.getContent()); |
|
||||||
} |
|
||||||
return result; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,375 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.alert.template.AlertTemplate; |
|
||||||
import org.apache.dolphinscheduler.alert.template.AlertTemplateFactory; |
|
||||||
import org.apache.dolphinscheduler.common.enums.ShowType; |
|
||||||
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
|
||||||
import org.apache.dolphinscheduler.common.utils.StringUtils; |
|
||||||
|
|
||||||
import org.apache.commons.mail.EmailException; |
|
||||||
import org.apache.commons.mail.HtmlEmail; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
import java.io.IOException; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
import java.util.Properties; |
|
||||||
|
|
||||||
import javax.mail.Authenticator; |
|
||||||
import javax.mail.Message; |
|
||||||
import javax.mail.MessagingException; |
|
||||||
import javax.mail.PasswordAuthentication; |
|
||||||
import javax.mail.Session; |
|
||||||
import javax.mail.Transport; |
|
||||||
import javax.mail.internet.InternetAddress; |
|
||||||
import javax.mail.internet.MimeBodyPart; |
|
||||||
import javax.mail.internet.MimeMessage; |
|
||||||
import javax.mail.internet.MimeMultipart; |
|
||||||
import javax.mail.internet.MimeUtility; |
|
||||||
|
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
/** |
|
||||||
* mail utils |
|
||||||
*/ |
|
||||||
public class MailUtils { |
|
||||||
|
|
||||||
public static final Logger logger = LoggerFactory.getLogger(MailUtils.class); |
|
||||||
|
|
||||||
public static final String MAIL_PROTOCOL = PropertyUtils.getString(Constants.MAIL_PROTOCOL); |
|
||||||
|
|
||||||
public static final String MAIL_SERVER_HOST = PropertyUtils.getString(Constants.MAIL_SERVER_HOST); |
|
||||||
|
|
||||||
public static final Integer MAIL_SERVER_PORT = PropertyUtils.getInt(Constants.MAIL_SERVER_PORT); |
|
||||||
|
|
||||||
public static final String MAIL_SENDER = PropertyUtils.getString(Constants.MAIL_SENDER); |
|
||||||
|
|
||||||
public static final String MAIL_USER = PropertyUtils.getString(Constants.MAIL_USER); |
|
||||||
|
|
||||||
public static final String MAIL_PASSWD = PropertyUtils.getString(Constants.MAIL_PASSWD); |
|
||||||
|
|
||||||
public static final Boolean MAIL_USE_START_TLS = PropertyUtils.getBoolean(Constants.MAIL_SMTP_STARTTLS_ENABLE); |
|
||||||
|
|
||||||
public static final Boolean MAIL_USE_SSL = PropertyUtils.getBoolean(Constants.MAIL_SMTP_SSL_ENABLE); |
|
||||||
|
|
||||||
public static final String XLS_FILE_PATH = PropertyUtils.getString(Constants.XLS_FILE_PATH, "/tmp/xls"); |
|
||||||
|
|
||||||
public static final String STARTTLS_ENABLE = PropertyUtils.getString(Constants.MAIL_SMTP_STARTTLS_ENABLE); |
|
||||||
|
|
||||||
public static final Boolean SSL_ENABLE = PropertyUtils.getBoolean(Constants.MAIL_SMTP_SSL_ENABLE); |
|
||||||
|
|
||||||
public static final String SSL_TRUST = PropertyUtils.getString(Constants.MAIL_SMTP_SSL_TRUST); |
|
||||||
|
|
||||||
public static final AlertTemplate alertTemplate = AlertTemplateFactory.getMessageTemplate(); |
|
||||||
|
|
||||||
//Solve the problem of messy Chinese name in excel attachment
|
|
||||||
static { |
|
||||||
System.setProperty("mail.mime.splitlongparameters", "false"); |
|
||||||
} |
|
||||||
|
|
||||||
private MailUtils() { |
|
||||||
throw new IllegalStateException(MailUtils.class.getName()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* send mail to receivers |
|
||||||
* |
|
||||||
* @param receivers the receiver list |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @param showType the show type |
|
||||||
* @return the result map |
|
||||||
*/ |
|
||||||
public static Map<String, Object> sendMails(Collection<String> receivers, String title, String content, String showType) { |
|
||||||
return sendMails(receivers, null, title, content, showType); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* send mail |
|
||||||
* |
|
||||||
* @param receivers the receiver list |
|
||||||
* @param receiversCc cc list |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @param showType the show type |
|
||||||
* @return the send result |
|
||||||
*/ |
|
||||||
public static Map<String, Object> sendMails(Collection<String> receivers, Collection<String> receiversCc, String title, String content, String showType) { |
|
||||||
Map<String, Object> retMap = new HashMap<>(); |
|
||||||
retMap.put(Constants.STATUS, false); |
|
||||||
|
|
||||||
// if there is no receivers && no receiversCc, no need to process
|
|
||||||
if (CollectionUtils.isEmpty(receivers) && CollectionUtils.isEmpty(receiversCc)) { |
|
||||||
return retMap; |
|
||||||
} |
|
||||||
|
|
||||||
receivers.removeIf(StringUtils::isEmpty); |
|
||||||
|
|
||||||
if (showType.equals(ShowType.TABLE.getDescp()) || showType.equals(ShowType.TEXT.getDescp())) { |
|
||||||
// send email
|
|
||||||
HtmlEmail email = new HtmlEmail(); |
|
||||||
|
|
||||||
try { |
|
||||||
Session session = getSession(); |
|
||||||
email.setMailSession(session); |
|
||||||
email.setFrom(MAIL_SENDER); |
|
||||||
email.setCharset(Constants.UTF_8); |
|
||||||
if (CollectionUtils.isNotEmpty(receivers)) { |
|
||||||
// receivers mail
|
|
||||||
for (String receiver : receivers) { |
|
||||||
email.addTo(receiver); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (CollectionUtils.isNotEmpty(receiversCc)) { |
|
||||||
//cc
|
|
||||||
for (String receiverCc : receiversCc) { |
|
||||||
email.addCc(receiverCc); |
|
||||||
} |
|
||||||
} |
|
||||||
// sender mail
|
|
||||||
return getStringObjectMap(title, content, showType, retMap, email); |
|
||||||
} catch (Exception e) { |
|
||||||
handleException(receivers, retMap, e); |
|
||||||
} |
|
||||||
} else if (showType.equals(ShowType.ATTACHMENT.getDescp()) || showType.equals(ShowType.TABLEATTACHMENT.getDescp())) { |
|
||||||
try { |
|
||||||
|
|
||||||
String partContent = (showType.equals(ShowType.ATTACHMENT.getDescp()) ? "Please see the attachment " + title + Constants.EXCEL_SUFFIX_XLS : htmlTable(content, false)); |
|
||||||
|
|
||||||
attachment(receivers, receiversCc, title, content, partContent); |
|
||||||
|
|
||||||
retMap.put(Constants.STATUS, true); |
|
||||||
return retMap; |
|
||||||
} catch (Exception e) { |
|
||||||
handleException(receivers, retMap, e); |
|
||||||
return retMap; |
|
||||||
} |
|
||||||
} |
|
||||||
return retMap; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* html table content |
|
||||||
* |
|
||||||
* @param content the content |
|
||||||
* @param showAll if show the whole content |
|
||||||
* @return the html table form |
|
||||||
*/ |
|
||||||
private static String htmlTable(String content, boolean showAll) { |
|
||||||
return alertTemplate.getMessageFromTemplate(content, ShowType.TABLE, showAll); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* html table content |
|
||||||
* |
|
||||||
* @param content the content |
|
||||||
* @return the html table form |
|
||||||
*/ |
|
||||||
private static String htmlTable(String content) { |
|
||||||
return htmlTable(content, true); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* html text content |
|
||||||
* |
|
||||||
* @param content the content |
|
||||||
* @return text in html form |
|
||||||
*/ |
|
||||||
private static String htmlText(String content) { |
|
||||||
return alertTemplate.getMessageFromTemplate(content, ShowType.TEXT); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* send mail as Excel attachment |
|
||||||
* |
|
||||||
* @param receivers the receiver list |
|
||||||
* @param title the title |
|
||||||
*/ |
|
||||||
private static void attachment(Collection<String> receivers, Collection<String> receiversCc, String title, String content, String partContent) throws Exception { |
|
||||||
MimeMessage msg = getMimeMessage(receivers); |
|
||||||
|
|
||||||
attachContent(receiversCc, title, content, partContent, msg); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get MimeMessage |
|
||||||
* |
|
||||||
* @param receivers receivers |
|
||||||
* @return the MimeMessage |
|
||||||
*/ |
|
||||||
private static MimeMessage getMimeMessage(Collection<String> receivers) throws MessagingException { |
|
||||||
|
|
||||||
// 1. The first step in creating mail: creating session
|
|
||||||
Session session = getSession(); |
|
||||||
// Setting debug mode, can be turned off
|
|
||||||
session.setDebug(false); |
|
||||||
|
|
||||||
// 2. creating mail: Creating a MimeMessage
|
|
||||||
MimeMessage msg = new MimeMessage(session); |
|
||||||
// 3. set sender
|
|
||||||
msg.setFrom(new InternetAddress(MAIL_SENDER)); |
|
||||||
// 4. set receivers
|
|
||||||
for (String receiver : receivers) { |
|
||||||
msg.addRecipients(Message.RecipientType.TO, InternetAddress.parse(receiver)); |
|
||||||
} |
|
||||||
return msg; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* get session |
|
||||||
* |
|
||||||
* @return the new Session |
|
||||||
*/ |
|
||||||
private static Session getSession() { |
|
||||||
Properties props = new Properties(); |
|
||||||
props.setProperty(Constants.MAIL_HOST, MAIL_SERVER_HOST); |
|
||||||
props.setProperty(Constants.MAIL_PORT, String.valueOf(MAIL_SERVER_PORT)); |
|
||||||
props.setProperty(Constants.MAIL_SMTP_AUTH, Constants.STRING_TRUE); |
|
||||||
props.setProperty(Constants.MAIL_TRANSPORT_PROTOCOL, MAIL_PROTOCOL); |
|
||||||
props.setProperty(Constants.MAIL_SMTP_STARTTLS_ENABLE, STARTTLS_ENABLE); |
|
||||||
if (Boolean.TRUE.equals(SSL_ENABLE)) { |
|
||||||
props.setProperty(Constants.MAIL_SMTP_SSL_ENABLE, "true"); |
|
||||||
props.setProperty(Constants.MAIL_SMTP_SSL_TRUST, SSL_TRUST); |
|
||||||
} |
|
||||||
|
|
||||||
Authenticator auth = new Authenticator() { |
|
||||||
@Override |
|
||||||
protected PasswordAuthentication getPasswordAuthentication() { |
|
||||||
// mail username and password
|
|
||||||
return new PasswordAuthentication(MAIL_USER, MAIL_PASSWD); |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
return Session.getInstance(props, auth); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* attach content |
|
||||||
* |
|
||||||
* @param receiversCc the cc list |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @param partContent the partContent |
|
||||||
* @param msg the message |
|
||||||
*/ |
|
||||||
private static void attachContent(Collection<String> receiversCc, String title, String content, String partContent, MimeMessage msg) throws MessagingException, IOException { |
|
||||||
/* |
|
||||||
* set receiverCc |
|
||||||
*/ |
|
||||||
if (CollectionUtils.isNotEmpty(receiversCc)) { |
|
||||||
for (String receiverCc : receiversCc) { |
|
||||||
msg.addRecipients(Message.RecipientType.CC, InternetAddress.parse(receiverCc)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// set subject
|
|
||||||
msg.setSubject(title); |
|
||||||
MimeMultipart partList = new MimeMultipart(); |
|
||||||
// set signature
|
|
||||||
MimeBodyPart part1 = new MimeBodyPart(); |
|
||||||
part1.setContent(partContent, Constants.TEXT_HTML_CHARSET_UTF_8); |
|
||||||
// set attach file
|
|
||||||
MimeBodyPart part2 = new MimeBodyPart(); |
|
||||||
File file = new File(XLS_FILE_PATH + Constants.SINGLE_SLASH + title + Constants.EXCEL_SUFFIX_XLS); |
|
||||||
if (!file.getParentFile().exists()) { |
|
||||||
file.getParentFile().mkdirs(); |
|
||||||
} |
|
||||||
// make excel file
|
|
||||||
|
|
||||||
ExcelUtils.genExcelFile(content, title, XLS_FILE_PATH); |
|
||||||
|
|
||||||
part2.attachFile(file); |
|
||||||
part2.setFileName(MimeUtility.encodeText(title + Constants.EXCEL_SUFFIX_XLS, Constants.UTF_8, "B")); |
|
||||||
// add components to collection
|
|
||||||
partList.addBodyPart(part1); |
|
||||||
partList.addBodyPart(part2); |
|
||||||
msg.setContent(partList); |
|
||||||
// 5. send Transport
|
|
||||||
Transport.send(msg); |
|
||||||
// 6. delete saved file
|
|
||||||
deleteFile(file); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* the string object map |
|
||||||
* |
|
||||||
* @param title the title |
|
||||||
* @param content the content |
|
||||||
* @param showType the showType |
|
||||||
* @param retMap the result map |
|
||||||
* @param email the email |
|
||||||
* @return the result map |
|
||||||
*/ |
|
||||||
private static Map<String, Object> getStringObjectMap(String title, String content, String showType, Map<String, Object> retMap, HtmlEmail email) throws EmailException { |
|
||||||
|
|
||||||
/* |
|
||||||
* the subject of the message to be sent |
|
||||||
*/ |
|
||||||
email.setSubject(title); |
|
||||||
/* |
|
||||||
* to send information, you can use HTML tags in mail content because of the use of HtmlEmail |
|
||||||
*/ |
|
||||||
if (showType.equals(ShowType.TABLE.getDescp())) { |
|
||||||
email.setMsg(htmlTable(content)); |
|
||||||
} else if (showType.equals(ShowType.TEXT.getDescp())) { |
|
||||||
email.setMsg(htmlText(content)); |
|
||||||
} |
|
||||||
|
|
||||||
// send
|
|
||||||
email.send(); |
|
||||||
|
|
||||||
retMap.put(Constants.STATUS, true); |
|
||||||
|
|
||||||
return retMap; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* file delete |
|
||||||
* |
|
||||||
* @param file the file to delete |
|
||||||
*/ |
|
||||||
public static void deleteFile(File file) { |
|
||||||
if (file.exists()) { |
|
||||||
if (file.delete()) { |
|
||||||
logger.info("delete success: {}", file.getAbsolutePath() + file.getName()); |
|
||||||
} else { |
|
||||||
logger.info("delete fail: {}", file.getAbsolutePath() + file.getName()); |
|
||||||
} |
|
||||||
} else { |
|
||||||
logger.info("file not exists: {}", file.getAbsolutePath() + file.getName()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* handle exception |
|
||||||
* |
|
||||||
* @param receivers the receiver list |
|
||||||
* @param retMap the result map |
|
||||||
* @param e the exception |
|
||||||
*/ |
|
||||||
private static void handleException(Collection<String> receivers, Map<String, Object> retMap, Exception e) { |
|
||||||
logger.error("Send email to {} failed", receivers, e); |
|
||||||
retMap.put(Constants.MESSAGE, "Send email to {" + String.join(",", receivers) + "} failed," + e.toString()); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager; |
||||||
|
import org.apache.dolphinscheduler.alert.plugin.DolphinPluginLoader; |
||||||
|
import org.apache.dolphinscheduler.alert.plugin.DolphinPluginManagerConfig; |
||||||
|
import org.apache.dolphinscheduler.alert.runner.AlertSender; |
||||||
|
import org.apache.dolphinscheduler.alert.utils.Constants; |
||||||
|
import org.apache.dolphinscheduler.dao.AlertDao; |
||||||
|
import org.apache.dolphinscheduler.dao.DaoFactory; |
||||||
|
import org.apache.dolphinscheduler.dao.PluginDao; |
||||||
|
import org.apache.dolphinscheduler.remote.NettyRemotingServer; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.powermock.api.mockito.PowerMockito; |
||||||
|
import org.powermock.core.classloader.annotations.PrepareForTest; |
||||||
|
import org.powermock.modules.junit4.PowerMockRunner; |
||||||
|
|
||||||
|
@RunWith(PowerMockRunner.class) |
||||||
|
@PrepareForTest({AlertServer.class,DaoFactory.class}) |
||||||
|
public class AlertServerTest { |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testMain() throws Exception { |
||||||
|
AlertDao alertDao = PowerMockito.mock(AlertDao.class); |
||||||
|
PowerMockito.mockStatic(DaoFactory.class); |
||||||
|
PowerMockito.when(DaoFactory.getDaoInstance(AlertDao.class)).thenReturn(alertDao); |
||||||
|
|
||||||
|
PluginDao pluginDao = PowerMockito.mock(PluginDao.class); |
||||||
|
PowerMockito.when(DaoFactory.getDaoInstance(PluginDao.class)).thenReturn(pluginDao); |
||||||
|
|
||||||
|
AlertChannel alertChannelMock = PowerMockito.mock(AlertChannel.class); |
||||||
|
|
||||||
|
AlertPluginManager alertPluginManager = PowerMockito.mock(AlertPluginManager.class); |
||||||
|
PowerMockito.whenNew(AlertPluginManager.class).withNoArguments().thenReturn(alertPluginManager); |
||||||
|
ConcurrentHashMap alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
alertChannelMap.put("pluginName",alertChannelMock); |
||||||
|
PowerMockito.when(alertPluginManager.getAlertChannelMap()).thenReturn(alertChannelMap); |
||||||
|
|
||||||
|
DolphinPluginManagerConfig alertPluginManagerConfig = PowerMockito.mock(DolphinPluginManagerConfig.class); |
||||||
|
PowerMockito.whenNew(DolphinPluginManagerConfig.class).withNoArguments().thenReturn(alertPluginManagerConfig); |
||||||
|
|
||||||
|
NettyRemotingServer nettyRemotingServer = PowerMockito.mock(NettyRemotingServer.class); |
||||||
|
PowerMockito.whenNew(NettyRemotingServer.class).withAnyArguments().thenReturn(nettyRemotingServer); |
||||||
|
AlertSender alertSender = PowerMockito.mock(AlertSender.class); |
||||||
|
PowerMockito.whenNew(AlertSender.class).withAnyArguments().thenReturn(alertSender); |
||||||
|
|
||||||
|
DolphinPluginLoader dolphinPluginLoader = PowerMockito.mock(DolphinPluginLoader.class); |
||||||
|
PowerMockito.whenNew(DolphinPluginLoader.class).withAnyArguments().thenReturn(dolphinPluginLoader); |
||||||
|
|
||||||
|
AlertServer alertServer = AlertServer.getInstance(); |
||||||
|
Assert.assertNotNull(alertServer); |
||||||
|
|
||||||
|
new Thread(() -> { |
||||||
|
alertServer.start(); }) |
||||||
|
.start(); |
||||||
|
|
||||||
|
Thread.sleep(5 * Constants.ALERT_SCAN_INTERVAL); |
||||||
|
|
||||||
|
alertServer.stop(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.alert.AlertServer; |
||||||
|
import org.apache.dolphinscheduler.alert.utils.Constants; |
||||||
|
import org.apache.dolphinscheduler.alert.utils.PropertyUtils; |
||||||
|
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Ignore; |
||||||
|
import org.junit.Test; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* AlertPluginManager Tester. |
||||||
|
*/ |
||||||
|
@Ignore |
||||||
|
public class AlertPluginManagerTest { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AlertPluginManagerTest.class); |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testLoadPlugins() throws Exception { |
||||||
|
logger.info("begin test AlertPluginManagerTest"); |
||||||
|
AlertPluginManager alertPluginManager = new AlertPluginManager(); |
||||||
|
DolphinPluginManagerConfig alertPluginManagerConfig = new DolphinPluginManagerConfig(); |
||||||
|
String path = DolphinPluginLoader.class.getClassLoader().getResource("").getPath(); |
||||||
|
alertPluginManagerConfig.setPlugins(path + "../../../dolphinscheduler-alert-plugin/dolphinscheduler-alert-email/pom.xml"); |
||||||
|
if (StringUtils.isNotBlank(PropertyUtils.getString(AlertServer.ALERT_PLUGIN_DIR))) { |
||||||
|
alertPluginManagerConfig.setInstalledPluginsDir(org.apache.dolphinscheduler.alert.utils.PropertyUtils.getString(AlertServer.ALERT_PLUGIN_DIR, Constants.ALERT_PLUGIN_PATH).trim()); |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(PropertyUtils.getString(AlertServer.MAVEN_LOCAL_REPOSITORY))) { |
||||||
|
alertPluginManagerConfig.setMavenLocalRepository(PropertyUtils.getString(AlertServer.MAVEN_LOCAL_REPOSITORY).trim()); |
||||||
|
} |
||||||
|
|
||||||
|
DolphinPluginLoader alertPluginLoader = new DolphinPluginLoader(alertPluginManagerConfig, ImmutableList.of(alertPluginManager)); |
||||||
|
try { |
||||||
|
alertPluginLoader.loadPlugins(); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException("load Alert Plugin Failed !", e); |
||||||
|
} |
||||||
|
|
||||||
|
Assert.assertNotNull(alertPluginManager.getAlertChannelFactoryMap().get("email alert")); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.plugin; |
||||||
|
|
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Ignore; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList; |
||||||
|
|
||||||
|
/** |
||||||
|
* DolphinPluginLoader Tester. |
||||||
|
*/ |
||||||
|
@Ignore |
||||||
|
public class DolphinPluginLoaderTest { |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() throws Exception { |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void after() throws Exception { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Method: loadPlugins() |
||||||
|
*/ |
||||||
|
@Test |
||||||
|
public void testLoadPlugins() throws Exception { |
||||||
|
AlertPluginManager alertPluginManager = new AlertPluginManager(); |
||||||
|
DolphinPluginManagerConfig alertPluginManagerConfig = new DolphinPluginManagerConfig(); |
||||||
|
String path = DolphinPluginLoader.class.getClassLoader().getResource("").getPath(); |
||||||
|
alertPluginManagerConfig.setPlugins(path + "../../../dolphinscheduler-alert-plugin/dolphinscheduler-alert-email/pom.xml"); |
||||||
|
DolphinPluginLoader alertPluginLoader = new DolphinPluginLoader(alertPluginManagerConfig, ImmutableList.of(alertPluginManager)); |
||||||
|
try { |
||||||
|
alertPluginLoader.loadPlugins(); |
||||||
|
} catch (Exception e) { |
||||||
|
throw new RuntimeException("load Alert Plugin Failed !", e); |
||||||
|
} |
||||||
|
|
||||||
|
Assert.assertNotNull(alertPluginManager.getAlertChannelFactoryMap().get("email alert")); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.processor; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager; |
||||||
|
import org.apache.dolphinscheduler.dao.AlertDao; |
||||||
|
import org.apache.dolphinscheduler.dao.PluginDao; |
||||||
|
import org.apache.dolphinscheduler.remote.command.Command; |
||||||
|
import org.apache.dolphinscheduler.remote.command.CommandType; |
||||||
|
import org.apache.dolphinscheduler.remote.command.alert.AlertSendRequestCommand; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.powermock.api.mockito.PowerMockito; |
||||||
|
|
||||||
|
import io.netty.channel.Channel; |
||||||
|
|
||||||
|
/** |
||||||
|
* alert request processor test |
||||||
|
*/ |
||||||
|
public class AlertRequestProcessorTest { |
||||||
|
|
||||||
|
private AlertDao alertDao; |
||||||
|
private PluginDao pluginDao; |
||||||
|
private AlertPluginManager alertPluginManager; |
||||||
|
|
||||||
|
private AlertRequestProcessor alertRequestProcessor; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() { |
||||||
|
alertDao = PowerMockito.mock(AlertDao.class); |
||||||
|
pluginDao = PowerMockito.mock(PluginDao.class); |
||||||
|
alertPluginManager = PowerMockito.mock(AlertPluginManager.class); |
||||||
|
alertRequestProcessor = new AlertRequestProcessor(alertDao,alertPluginManager,pluginDao); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testProcess() { |
||||||
|
Channel channel = PowerMockito.mock(Channel.class); |
||||||
|
AlertSendRequestCommand alertSendRequestCommand = new AlertSendRequestCommand(1,"title","content"); |
||||||
|
Command reqCommand = alertSendRequestCommand.convert2Command(); |
||||||
|
Assert.assertEquals(CommandType.ALERT_SEND_REQUEST,reqCommand.getType()); |
||||||
|
alertRequestProcessor.process(channel,reqCommand); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,181 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.alert.runner; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager; |
||||||
|
import org.apache.dolphinscheduler.dao.AlertDao; |
||||||
|
import org.apache.dolphinscheduler.dao.PluginDao; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Alert; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.AlertPluginInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.PluginDefine; |
||||||
|
import org.apache.dolphinscheduler.remote.command.alert.AlertSendResponseCommand; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertChannel; |
||||||
|
import org.apache.dolphinscheduler.spi.alert.AlertResult; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
import org.junit.Assert; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.mockito.Mockito; |
||||||
|
import org.powermock.api.mockito.PowerMockito; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* alert sender test |
||||||
|
*/ |
||||||
|
public class AlertSenderTest { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AlertSenderTest.class); |
||||||
|
|
||||||
|
private AlertDao alertDao; |
||||||
|
private PluginDao pluginDao; |
||||||
|
private AlertPluginManager alertPluginManager; |
||||||
|
|
||||||
|
private AlertSender alertSender; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() { |
||||||
|
alertDao = PowerMockito.mock(AlertDao.class); |
||||||
|
pluginDao = PowerMockito.mock(PluginDao.class); |
||||||
|
alertPluginManager = PowerMockito.mock(AlertPluginManager.class); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testSyncHandler() { |
||||||
|
|
||||||
|
int alertGroupId = 1; |
||||||
|
String title = "alert mail test title"; |
||||||
|
String content = "alert mail test content"; |
||||||
|
alertSender = new AlertSender(alertDao,alertPluginManager,pluginDao); |
||||||
|
|
||||||
|
//1.alert instance does not exist
|
||||||
|
PowerMockito.when(alertDao.listInstanceByAlertGroupId(alertGroupId)).thenReturn(null); |
||||||
|
|
||||||
|
AlertSendResponseCommand alertSendResponseCommand = alertSender.syncHandler(alertGroupId, title, content); |
||||||
|
Assert.assertFalse(alertSendResponseCommand.getResStatus()); |
||||||
|
alertSendResponseCommand.getResResults().forEach(result -> |
||||||
|
logger.info("alert send response result, status:{}, message:{}",result.getStatus(),result.getMessage())); |
||||||
|
|
||||||
|
//2.alert plugin does not exist
|
||||||
|
int pluginDefineId = 1; |
||||||
|
String pluginInstanceParams = "alert-instance-mail-params"; |
||||||
|
String pluginInstanceName = "alert-instance-mail"; |
||||||
|
List<AlertPluginInstance> alertInstanceList = new ArrayList<>(); |
||||||
|
AlertPluginInstance alertPluginInstance = new AlertPluginInstance( |
||||||
|
pluginDefineId,pluginInstanceParams,pluginInstanceName); |
||||||
|
alertInstanceList.add(alertPluginInstance); |
||||||
|
PowerMockito.when(alertDao.listInstanceByAlertGroupId(1)).thenReturn(alertInstanceList); |
||||||
|
|
||||||
|
String pluginName = "alert-plugin-mail"; |
||||||
|
PluginDefine pluginDefine = new PluginDefine(pluginName,"1",null); |
||||||
|
PowerMockito.when(pluginDao.getPluginDefineById(pluginDefineId)).thenReturn(pluginDefine); |
||||||
|
|
||||||
|
alertSendResponseCommand = alertSender.syncHandler(alertGroupId, title, content); |
||||||
|
Assert.assertFalse(alertSendResponseCommand.getResStatus()); |
||||||
|
alertSendResponseCommand.getResResults().forEach(result -> |
||||||
|
logger.info("alert send response result, status:{}, message:{}",result.getStatus(),result.getMessage())); |
||||||
|
|
||||||
|
//3.alert result value is null
|
||||||
|
AlertChannel alertChannelMock = PowerMockito.mock(AlertChannel.class); |
||||||
|
PowerMockito.when(alertChannelMock.process(Mockito.any())).thenReturn(null); |
||||||
|
Map<String, AlertChannel> alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
alertChannelMap.put(pluginName,alertChannelMock); |
||||||
|
PowerMockito.when(alertPluginManager.getAlertChannelMap()).thenReturn(alertChannelMap); |
||||||
|
|
||||||
|
alertSendResponseCommand = alertSender.syncHandler(alertGroupId, title, content); |
||||||
|
Assert.assertFalse(alertSendResponseCommand.getResStatus()); |
||||||
|
alertSendResponseCommand.getResResults().forEach(result -> |
||||||
|
logger.info("alert send response result, status:{}, message:{}",result.getStatus(),result.getMessage())); |
||||||
|
|
||||||
|
//4.abnormal information inside the alert plug-in code
|
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus(String.valueOf(false)); |
||||||
|
alertResult.setMessage("Abnormal information inside the alert plug-in code"); |
||||||
|
PowerMockito.when(alertChannelMock.process(Mockito.any())).thenReturn(alertResult); |
||||||
|
alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
alertChannelMap.put(pluginName,alertChannelMock); |
||||||
|
PowerMockito.when(alertPluginManager.getAlertChannelMap()).thenReturn(alertChannelMap); |
||||||
|
|
||||||
|
alertSendResponseCommand = alertSender.syncHandler(alertGroupId, title, content); |
||||||
|
Assert.assertFalse(alertSendResponseCommand.getResStatus()); |
||||||
|
alertSendResponseCommand.getResResults().forEach(result -> |
||||||
|
logger.info("alert send response result, status:{}, message:{}",result.getStatus(),result.getMessage())); |
||||||
|
|
||||||
|
//5.alert plugin send success
|
||||||
|
alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus(String.valueOf(true)); |
||||||
|
alertResult.setMessage(String.format("Alert Plugin %s send success",pluginInstanceName)); |
||||||
|
PowerMockito.when(alertChannelMock.process(Mockito.any())).thenReturn(alertResult); |
||||||
|
alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
alertChannelMap.put(pluginName,alertChannelMock); |
||||||
|
PowerMockito.when(alertPluginManager.getAlertChannelMap()).thenReturn(alertChannelMap); |
||||||
|
|
||||||
|
alertSendResponseCommand = alertSender.syncHandler(alertGroupId, title, content); |
||||||
|
Assert.assertTrue(alertSendResponseCommand.getResStatus()); |
||||||
|
alertSendResponseCommand.getResResults().forEach(result -> |
||||||
|
logger.info("alert send response result, status:{}, message:{}",result.getStatus(),result.getMessage())); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testRun() { |
||||||
|
int alertGroupId = 1; |
||||||
|
String title = "alert mail test title"; |
||||||
|
String content = "alert mail test content"; |
||||||
|
List<Alert> alertList = new ArrayList<>(); |
||||||
|
Alert alert = new Alert(); |
||||||
|
alert.setAlertGroupId(alertGroupId); |
||||||
|
alert.setTitle(title); |
||||||
|
alert.setContent(content); |
||||||
|
alertList.add(alert); |
||||||
|
|
||||||
|
alertSender = new AlertSender(alertList,alertDao,alertPluginManager,pluginDao); |
||||||
|
|
||||||
|
int pluginDefineId = 1; |
||||||
|
String pluginInstanceParams = "alert-instance-mail-params"; |
||||||
|
String pluginInstanceName = "alert-instance-mail"; |
||||||
|
List<AlertPluginInstance> alertInstanceList = new ArrayList<>(); |
||||||
|
AlertPluginInstance alertPluginInstance = new AlertPluginInstance( |
||||||
|
pluginDefineId,pluginInstanceParams,pluginInstanceName); |
||||||
|
alertInstanceList.add(alertPluginInstance); |
||||||
|
PowerMockito.when(alertDao.listInstanceByAlertGroupId(alertGroupId)).thenReturn(alertInstanceList); |
||||||
|
|
||||||
|
String pluginName = "alert-plugin-mail"; |
||||||
|
PluginDefine pluginDefine = new PluginDefine(pluginName,"1",null); |
||||||
|
PowerMockito.when(pluginDao.getPluginDefineById(pluginDefineId)).thenReturn(pluginDefine); |
||||||
|
|
||||||
|
AlertResult alertResult = new AlertResult(); |
||||||
|
alertResult.setStatus(String.valueOf(true)); |
||||||
|
alertResult.setMessage(String.format("Alert Plugin %s send success",pluginInstanceName)); |
||||||
|
AlertChannel alertChannelMock = PowerMockito.mock(AlertChannel.class); |
||||||
|
PowerMockito.when(alertChannelMock.process(Mockito.any())).thenReturn(alertResult); |
||||||
|
ConcurrentHashMap alertChannelMap = new ConcurrentHashMap<>(); |
||||||
|
alertChannelMap.put(pluginName,alertChannelMock); |
||||||
|
PowerMockito.when(alertPluginManager.getAlertChannelMap()).thenReturn(alertChannelMap); |
||||||
|
Assert.assertTrue(Boolean.parseBoolean(alertResult.getStatus())); |
||||||
|
alertSender.run(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,65 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.apache.dolphinscheduler.alert.template; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.alert.template.impl.DefaultHTMLTemplate; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.Constants; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.PropertyUtils; |
|
||||||
import org.junit.Test; |
|
||||||
import org.junit.runner.RunWith; |
|
||||||
import org.mockito.Mockito; |
|
||||||
import org.powermock.api.mockito.PowerMockito; |
|
||||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
|
||||||
import org.powermock.modules.junit4.PowerMockRunner; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import static org.mockito.Mockito.*; |
|
||||||
import static org.junit.Assert.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* test class for AlertTemplateFactory |
|
||||||
*/ |
|
||||||
@RunWith(PowerMockRunner.class) |
|
||||||
@PrepareForTest(PropertyUtils.class) |
|
||||||
public class AlertTemplateFactoryTest { |
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(AlertTemplateFactoryTest.class); |
|
||||||
|
|
||||||
/** |
|
||||||
* GetMessageTemplate method test |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void testGetMessageTemplate(){ |
|
||||||
|
|
||||||
PowerMockito.mockStatic(PropertyUtils.class); |
|
||||||
|
|
||||||
AlertTemplate defaultTemplate = AlertTemplateFactory.getMessageTemplate(); |
|
||||||
|
|
||||||
assertTrue(defaultTemplate instanceof DefaultHTMLTemplate); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* GetMessageTemplate method throw Exception test |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void testGetMessageTemplateException(){ |
|
||||||
|
|
||||||
AlertTemplate defaultTemplate = AlertTemplateFactory.getMessageTemplate(); |
|
||||||
assertTrue(defaultTemplate instanceof DefaultHTMLTemplate); |
|
||||||
} |
|
||||||
} |
|
@ -1,96 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.apache.dolphinscheduler.alert.template.impl; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.utils.*; |
|
||||||
import org.apache.dolphinscheduler.alert.utils.Constants; |
|
||||||
import org.apache.dolphinscheduler.common.enums.ShowType; |
|
||||||
import org.junit.Test; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.LinkedHashMap; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
|
|
||||||
/** |
|
||||||
* test class for DefaultHTMLTemplate |
|
||||||
*/ |
|
||||||
public class DefaultHTMLTemplateTest{ |
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(DefaultHTMLTemplateTest.class); |
|
||||||
|
|
||||||
/** |
|
||||||
* only need test method GetMessageFromTemplate |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void testGetMessageFromTemplate(){ |
|
||||||
|
|
||||||
DefaultHTMLTemplate template = new DefaultHTMLTemplate(); |
|
||||||
|
|
||||||
String tableTypeMessage = template.getMessageFromTemplate(list2String(), ShowType.TABLE,true); |
|
||||||
|
|
||||||
assertEquals(tableTypeMessage,generateMockTableTypeResultByHand()); |
|
||||||
|
|
||||||
String textTypeMessage = template.getMessageFromTemplate(list2String(), ShowType.TEXT,true); |
|
||||||
|
|
||||||
assertEquals(textTypeMessage,generateMockTextTypeResultByHand()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* generate some simulation data |
|
||||||
*/ |
|
||||||
private String list2String(){ |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
|
||||||
map1.put("mysql service name","mysql200"); |
|
||||||
map1.put("mysql address","192.168.xx.xx"); |
|
||||||
map1.put("database client connections","190"); |
|
||||||
map1.put("port","3306"); |
|
||||||
map1.put("no index of number","80"); |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map2 = new LinkedHashMap<>(); |
|
||||||
map2.put("mysql service name","mysql210"); |
|
||||||
map2.put("mysql address","192.168.xx.xx"); |
|
||||||
map2.put("database client connections","90"); |
|
||||||
map2.put("port","3306"); |
|
||||||
map2.put("no index of number","10"); |
|
||||||
|
|
||||||
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
|
||||||
maps.add(0,map1); |
|
||||||
maps.add(1,map2); |
|
||||||
String mapjson = JSONUtils.toJsonString(maps); |
|
||||||
logger.info(mapjson); |
|
||||||
|
|
||||||
return mapjson; |
|
||||||
} |
|
||||||
|
|
||||||
private String generateMockTableTypeResultByHand(){ |
|
||||||
|
|
||||||
return Constants.HTML_HEADER_PREFIX + |
|
||||||
"<thead><tr><th>mysql service name</th><th>mysql address</th><th>database client connections</th><th>port</th><th>no index of number</th></tr></thead>\n" + |
|
||||||
"<tr><td>mysql200</td><td>192.168.xx.xx</td><td>190</td><td>3306</td><td>80</td></tr><tr><td>mysql210</td><td>192.168.xx.xx</td><td>90</td><td>3306</td><td>10</td></tr>" + Constants.TABLE_BODY_HTML_TAIL; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private String generateMockTextTypeResultByHand(){ |
|
||||||
|
|
||||||
return Constants.HTML_HEADER_PREFIX + "<tr><td>{\"mysql service name\":\"mysql200\",\"mysql address\":\"192.168.xx.xx\",\"database client connections\":\"190\",\"port\":\"3306\",\"no index of number\":\"80\"}</td></tr><tr><td>{\"mysql service name\":\"mysql210\",\"mysql address\":\"192.168.xx.xx\",\"database client connections\":\"90\",\"port\":\"3306\",\"no index of number\":\"10\"}</td></tr>" + Constants.TABLE_BODY_HTML_TAIL; |
|
||||||
} |
|
||||||
} |
|
@ -1,120 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
import org.apache.http.client.config.RequestConfig; |
|
||||||
import org.apache.http.impl.client.CloseableHttpClient; |
|
||||||
import org.junit.Assert; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Test; |
|
||||||
import org.junit.runner.RunWith; |
|
||||||
import org.mockito.Mockito; |
|
||||||
import org.powermock.api.mockito.PowerMockito; |
|
||||||
import org.powermock.core.classloader.annotations.PowerMockIgnore; |
|
||||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
|
||||||
import org.powermock.modules.junit4.PowerMockRunner; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
@PrepareForTest(PropertyUtils.class) |
|
||||||
@RunWith(PowerMockRunner.class) |
|
||||||
@PowerMockIgnore("javax.net.ssl.*") |
|
||||||
public class DingTalkUtilsTest { |
|
||||||
Logger logger = LoggerFactory.getLogger(DingTalkUtilsTest.class); |
|
||||||
|
|
||||||
private static final String mockUrl = "https://oapi.dingtalk.com/robot/send?access_token=test"; |
|
||||||
private static final String mockKeyWords = "onway"; |
|
||||||
private static final String msg = "ding talk test"; |
|
||||||
|
|
||||||
@Before |
|
||||||
public void init(){ |
|
||||||
PowerMockito.mockStatic(PropertyUtils.class); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.DINGTALK_WEBHOOK)).thenReturn(mockUrl); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.DINGTALK_KEYWORD)).thenReturn(mockKeyWords); |
|
||||||
Mockito.when(PropertyUtils.getBoolean(Constants.DINGTALK_PROXY_ENABLE)).thenReturn(true); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.DINGTALK_PROXY)).thenReturn("proxy.com.cn"); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.DINGTALK_USER)).thenReturn("user"); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.DINGTALK_PASSWORD)).thenReturn("pswd"); |
|
||||||
Mockito.when(PropertyUtils.getInt(Constants.DINGTALK_PORT)).thenReturn(80); |
|
||||||
} |
|
||||||
|
|
||||||
// @Test
|
|
||||||
// @Ignore
|
|
||||||
// public void testSendMsg() {
|
|
||||||
// try {
|
|
||||||
// String msgTosend = "msg to send";
|
|
||||||
// logger.info(PropertyUtils.getString(Constants.DINGTALK_WEBHOOK));
|
|
||||||
// String rsp = DingTalkUtils.sendDingTalkMsg(msgTosend, Constants.UTF_8);
|
|
||||||
// logger.info("send msg result:{}",rsp);
|
|
||||||
// String errmsg = JSONUtils.parseObject(rsp).getString("errmsg");
|
|
||||||
// Assert.assertEquals("ok", errmsg);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@Test |
|
||||||
public void testCreateDefaultClient() { |
|
||||||
CloseableHttpClient client = DingTalkUtils.getDefaultClient();; |
|
||||||
try { |
|
||||||
Assert.assertNotNull(client); |
|
||||||
client.close(); |
|
||||||
} catch (IOException ex) { |
|
||||||
logger.info("close exception",ex.getMessage()); |
|
||||||
new Throwable(); |
|
||||||
} |
|
||||||
} |
|
||||||
@Test |
|
||||||
public void testCreateProxyClient() { |
|
||||||
CloseableHttpClient client = DingTalkUtils.getProxyClient(); |
|
||||||
try { |
|
||||||
Assert.assertNotNull(client); |
|
||||||
client.close(); |
|
||||||
} catch (IOException ex) { |
|
||||||
logger.info("close exception",ex.getMessage()); |
|
||||||
new Throwable(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@Test |
|
||||||
public void testProxyConfig() { |
|
||||||
RequestConfig rc = DingTalkUtils.getProxyConfig(); |
|
||||||
Assert.assertEquals(80, rc.getProxy().getPort()); |
|
||||||
Assert.assertEquals("proxy.com.cn", rc.getProxy().getHostName()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testDingTalkMsgToJson() { |
|
||||||
String jsonString = DingTalkUtils.textToJsonString("this is test"); |
|
||||||
|
|
||||||
logger.info(jsonString); |
|
||||||
String expect = "{\"text\":{\"content\":\"this is test\"},\"msgtype\":\"text\"}"; |
|
||||||
Assert.assertEquals(expect, jsonString); |
|
||||||
} |
|
||||||
@Test |
|
||||||
public void testDingTalkMsgUtf8() { |
|
||||||
String msg = DingTalkUtils.textToJsonString("this is test:中文"); |
|
||||||
|
|
||||||
logger.info("test support utf8, actual:" + msg); |
|
||||||
logger.info("test support utf8, actual:" + DingTalkUtils.IS_ENABLE_DING_TALK); |
|
||||||
String expect = "{\"text\":{\"content\":\"this is test:中文\"},\"msgtype\":\"text\"}"; |
|
||||||
Assert.assertEquals(expect, msg); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,283 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
|
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.enums.AlertType; |
|
||||||
import org.apache.dolphinscheduler.common.enums.ShowType; |
|
||||||
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
|
||||||
import org.apache.dolphinscheduler.dao.entity.Alert; |
|
||||||
import org.apache.dolphinscheduler.plugin.model.AlertData; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.LinkedHashMap; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import org.junit.Assert; |
|
||||||
import org.junit.Before; |
|
||||||
import org.junit.Test; |
|
||||||
import org.junit.runner.RunWith; |
|
||||||
import org.mockito.Mockito; |
|
||||||
import org.powermock.api.mockito.PowerMockito; |
|
||||||
import org.powermock.core.classloader.annotations.PrepareForTest; |
|
||||||
import org.powermock.modules.junit4.PowerMockRunner; |
|
||||||
|
|
||||||
/** |
|
||||||
* Please manually modify the configuration file before testing. |
|
||||||
* file: alert.properties |
|
||||||
* enterprise.wechat.corp.id |
|
||||||
* enterprise.wechat.secret |
|
||||||
* enterprise.wechat.token.url |
|
||||||
* enterprise.wechat.push.url |
|
||||||
* enterprise.wechat.send.msg |
|
||||||
* enterprise.wechat.agent.id |
|
||||||
* enterprise.wechat.users |
|
||||||
*/ |
|
||||||
@PrepareForTest(PropertyUtils.class) |
|
||||||
@RunWith(PowerMockRunner.class) |
|
||||||
public class EnterpriseWeChatUtilsTest { |
|
||||||
|
|
||||||
private static final String toParty = "wwc99134b6fc1edb6"; |
|
||||||
private static final String enterpriseWechatSecret = "Uuv2KFrkdf7SeKOsTDCpsTkpawXBMNRhFy6VKX5FV"; |
|
||||||
private static final String enterpriseWechatAgentId = "1000004"; |
|
||||||
private static final String enterpriseWechatUsers = "LiGang,journey"; |
|
||||||
private static final String msg = "hello world"; |
|
||||||
|
|
||||||
private static final String enterpriseWechatTeamSendMsg = "{\\\"toparty\\\":\\\"{toParty}\\\",\\\"agentid\\\":\\\"{agentId}\\\"" |
|
||||||
+ |
|
||||||
",\\\"msgtype\\\":\\\"text\\\",\\\"text\\\":{\\\"content\\\":\\\"{msg}\\\"},\\\"safe\\\":\\\"0\\\"}"; |
|
||||||
private static final String enterpriseWechatUserSendMsg = "{\\\"touser\\\":\\\"{toUser}\\\",\\\"agentid\\\":\\\"{agentId}\\\"" |
|
||||||
+ |
|
||||||
",\\\"msgtype\\\":\\\"markdown\\\",\\\"markdown\\\":{\\\"content\\\":\\\"{msg}\\\"}}"; |
|
||||||
|
|
||||||
@Before |
|
||||||
public void init() { |
|
||||||
PowerMockito.mockStatic(PropertyUtils.class); |
|
||||||
Mockito.when(PropertyUtils.getBoolean(Constants.ENTERPRISE_WECHAT_ENABLE)).thenReturn(true); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_USER_SEND_MSG)).thenReturn(enterpriseWechatUserSendMsg); |
|
||||||
Mockito.when(PropertyUtils.getString(Constants.ENTERPRISE_WECHAT_TEAM_SEND_MSG)).thenReturn(enterpriseWechatTeamSendMsg); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testIsEnable() { |
|
||||||
Boolean weChartEnable = EnterpriseWeChatUtils.isEnable(); |
|
||||||
Assert.assertTrue(weChartEnable); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testMakeTeamSendMsg1() { |
|
||||||
String sendMsg = EnterpriseWeChatUtils.makeTeamSendMsg(toParty, enterpriseWechatSecret, msg); |
|
||||||
Assert.assertTrue(sendMsg.contains(toParty)); |
|
||||||
Assert.assertTrue(sendMsg.contains(enterpriseWechatSecret)); |
|
||||||
Assert.assertTrue(sendMsg.contains(msg)); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testMakeTeamSendMsg2() { |
|
||||||
List<String> parties = new ArrayList<>(); |
|
||||||
parties.add(toParty); |
|
||||||
parties.add("test1"); |
|
||||||
|
|
||||||
String sendMsg = EnterpriseWeChatUtils.makeTeamSendMsg(parties, enterpriseWechatSecret, msg); |
|
||||||
Assert.assertTrue(sendMsg.contains(toParty)); |
|
||||||
Assert.assertTrue(sendMsg.contains(enterpriseWechatSecret)); |
|
||||||
Assert.assertTrue(sendMsg.contains(msg)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void tesMakeUserSendMsg1() { |
|
||||||
|
|
||||||
String sendMsg = EnterpriseWeChatUtils.makeUserSendMsg(enterpriseWechatUsers, enterpriseWechatAgentId, msg); |
|
||||||
Assert.assertTrue(sendMsg.contains(enterpriseWechatUsers)); |
|
||||||
Assert.assertTrue(sendMsg.contains(enterpriseWechatAgentId)); |
|
||||||
Assert.assertTrue(sendMsg.contains(msg)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void tesMakeUserSendMsg2() { |
|
||||||
List<String> users = new ArrayList<>(); |
|
||||||
users.add("user1"); |
|
||||||
users.add("user2"); |
|
||||||
|
|
||||||
String sendMsg = EnterpriseWeChatUtils.makeUserSendMsg(users, enterpriseWechatAgentId, msg); |
|
||||||
Assert.assertTrue(sendMsg.contains(users.get(0))); |
|
||||||
Assert.assertTrue(sendMsg.contains(users.get(1))); |
|
||||||
Assert.assertTrue(sendMsg.contains(enterpriseWechatAgentId)); |
|
||||||
Assert.assertTrue(sendMsg.contains(msg)); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testMarkdownByAlertForText() { |
|
||||||
Alert alertForText = createAlertForText(); |
|
||||||
AlertData alertData = new AlertData(); |
|
||||||
alertData.setTitle(alertForText.getTitle()) |
|
||||||
.setShowType(alertForText.getShowType().getDescp()) |
|
||||||
.setContent(alertForText.getContent()); |
|
||||||
String result = EnterpriseWeChatUtils.markdownByAlert(alertData); |
|
||||||
Assert.assertNotNull(result); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testMarkdownByAlertForTable() { |
|
||||||
Alert alertForText = createAlertForTable(); |
|
||||||
AlertData alertData = new AlertData(); |
|
||||||
alertData.setTitle(alertForText.getTitle()) |
|
||||||
.setShowType(alertForText.getShowType().getDescp()) |
|
||||||
.setContent(alertForText.getContent()); |
|
||||||
String result = EnterpriseWeChatUtils.markdownByAlert(alertData); |
|
||||||
Assert.assertNotNull(result); |
|
||||||
} |
|
||||||
|
|
||||||
private Alert createAlertForText() { |
|
||||||
String content = "[{\"id\":\"69\"," |
|
||||||
+ |
|
||||||
"\"name\":\"UserBehavior-0--1193959466\"," |
|
||||||
+ |
|
||||||
"\"Job name\":\"Start workflow\"," |
|
||||||
+ |
|
||||||
"\"State\":\"SUCCESS\"," |
|
||||||
+ |
|
||||||
"\"Recovery\":\"NO\"," |
|
||||||
+ |
|
||||||
"\"Run time\":\"1\"," |
|
||||||
+ |
|
||||||
"\"Start time\": \"2018-08-06 10:31:34.0\"," |
|
||||||
+ |
|
||||||
"\"End time\": \"2018-08-06 10:31:49.0\"," |
|
||||||
+ |
|
||||||
"\"Host\": \"192.168.xx.xx\"," |
|
||||||
+ |
|
||||||
"\"Notify group\" :\"4\"}]"; |
|
||||||
|
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TEXT); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(4); |
|
||||||
|
|
||||||
return alert; |
|
||||||
} |
|
||||||
|
|
||||||
private String list2String() { |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
|
||||||
map1.put("mysql service name", "mysql200"); |
|
||||||
map1.put("mysql address", "192.168.xx.xx"); |
|
||||||
map1.put("port", "3306"); |
|
||||||
map1.put("no index of number", "80"); |
|
||||||
map1.put("database client connections", "190"); |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map2 = new LinkedHashMap<>(); |
|
||||||
map2.put("mysql service name", "mysql210"); |
|
||||||
map2.put("mysql address", "192.168.xx.xx"); |
|
||||||
map2.put("port", "3306"); |
|
||||||
map2.put("no index of number", "10"); |
|
||||||
map2.put("database client connections", "90"); |
|
||||||
|
|
||||||
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
|
||||||
maps.add(0, map1); |
|
||||||
maps.add(1, map2); |
|
||||||
String mapjson = JSONUtils.toJsonString(maps); |
|
||||||
return mapjson; |
|
||||||
} |
|
||||||
|
|
||||||
private Alert createAlertForTable() { |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TABLE); |
|
||||||
String content = list2String(); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
return alert; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
// public void testSendSingleTeamWeChat() {
|
|
||||||
// try {
|
|
||||||
// String token = EnterpriseWeChatUtils.getToken();
|
|
||||||
// String msg = EnterpriseWeChatUtils.makeTeamSendMsg(partyId, agentId, "hello world");
|
|
||||||
// String resp = EnterpriseWeChatUtils.sendEnterpriseWeChat("utf-8", msg, token);
|
|
||||||
//
|
|
||||||
// String errmsg = JSONUtils.parseObject(resp).getString("errmsg");
|
|
||||||
// Assert.assertEquals("ok",errmsg);
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Test
|
|
||||||
// public void testSendMultiTeamWeChat() {
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// String token = EnterpriseWeChatUtils.getToken();
|
|
||||||
// String msg = EnterpriseWeChatUtils.makeTeamSendMsg(listPartyId, agentId, "hello world");
|
|
||||||
// String resp = EnterpriseWeChatUtils.sendEnterpriseWeChat("utf-8", msg, token);
|
|
||||||
//
|
|
||||||
// String errmsg = JSONUtils.parseObject(resp).getString("errmsg");
|
|
||||||
// Assert.assertEquals("ok",errmsg);
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Test
|
|
||||||
// public void testSendSingleUserWeChat() {
|
|
||||||
// try {
|
|
||||||
// String token = EnterpriseWeChatUtils.getToken();
|
|
||||||
// String msg = EnterpriseWeChatUtils.makeUserSendMsg(listUserId.stream().findFirst().get(), agentId, "your meeting room has been booked and will be synced to the 'mailbox' later \n" +
|
|
||||||
// ">**matter details** \n" +
|
|
||||||
// ">matter:<font color='info'>meeting</font> <br>" +
|
|
||||||
// ">organizer:@miglioguan \n" +
|
|
||||||
// ">participant:@miglioguan、@kunliu、@jamdeezhou、@kanexiong、@kisonwang \n" +
|
|
||||||
// "> \n" +
|
|
||||||
// ">meeting room:<font color='info'>Guangzhou TIT 1st Floor 301</font> \n" +
|
|
||||||
// ">date:<font color='warning'>May 18, 2018</font> \n" +
|
|
||||||
// ">time:<font color='comment'>9:00-11:00 am</font> \n" +
|
|
||||||
// "> \n" +
|
|
||||||
// ">please attend the meeting on time\n" +
|
|
||||||
// "> \n" +
|
|
||||||
// ">to modify the meeting information, please click: [Modify Meeting Information](https://work.weixin.qq.com)\"");
|
|
||||||
//
|
|
||||||
// String resp = EnterpriseWeChatUtils.sendEnterpriseWeChat("utf-8", msg, token);
|
|
||||||
//
|
|
||||||
// String errmsg = JSONUtils.parseObject(resp).getString("errmsg");
|
|
||||||
// Assert.assertEquals("ok",errmsg);
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Test
|
|
||||||
// public void testSendMultiUserWeChat() {
|
|
||||||
// try {
|
|
||||||
// String token = EnterpriseWeChatUtils.getToken();
|
|
||||||
//
|
|
||||||
// String msg = EnterpriseWeChatUtils.makeUserSendMsg(listUserId, agentId, "hello world");
|
|
||||||
// String resp = EnterpriseWeChatUtils.sendEnterpriseWeChat("utf-8", msg, token);
|
|
||||||
//
|
|
||||||
// String errmsg = JSONUtils.parseObject(resp).getString("errmsg");
|
|
||||||
// Assert.assertEquals("ok",errmsg);
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
} |
|
@ -1,190 +0,0 @@ |
|||||||
/* |
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
|
||||||
* contributor license agreements. See the NOTICE file distributed with |
|
||||||
* this work for additional information regarding copyright ownership. |
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
|
||||||
* (the "License"); you may not use this file except in compliance with |
|
||||||
* the License. You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
*/ |
|
||||||
package org.apache.dolphinscheduler.alert.utils; |
|
||||||
|
|
||||||
|
|
||||||
import org.apache.dolphinscheduler.common.enums.AlertType; |
|
||||||
import org.apache.dolphinscheduler.common.enums.ShowType; |
|
||||||
import org.apache.dolphinscheduler.dao.AlertDao; |
|
||||||
import org.apache.dolphinscheduler.dao.DaoFactory; |
|
||||||
import org.apache.dolphinscheduler.dao.entity.Alert; |
|
||||||
import org.apache.dolphinscheduler.dao.entity.User; |
|
||||||
import org.junit.Assert; |
|
||||||
import org.junit.Test; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.util.*; |
|
||||||
import org.apache.dolphinscheduler.common.utils.*; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
*/ |
|
||||||
public class MailUtilsTest { |
|
||||||
private static final Logger logger = LoggerFactory.getLogger(MailUtilsTest.class); |
|
||||||
@Test |
|
||||||
public void testSendMails() { |
|
||||||
String[] receivers = new String[]{"347801120@qq.com"}; |
|
||||||
String[] receiversCc = new String[]{"347801120@qq.com"}; |
|
||||||
|
|
||||||
String content ="[\"id:69\"," + |
|
||||||
"\"name:UserBehavior-0--1193959466\"," + |
|
||||||
"\"Job name: Start workflow\"," + |
|
||||||
"\"State: SUCCESS\"," + |
|
||||||
"\"Recovery:NO\"," + |
|
||||||
"\"Run time: 1\"," + |
|
||||||
"\"Start time: 2018-08-06 10:31:34.0\"," + |
|
||||||
"\"End time: 2018-08-06 10:31:49.0\"," + |
|
||||||
"\"Host: 192.168.xx.xx\"," + |
|
||||||
"\"Notify group :4\"]"; |
|
||||||
|
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TEXT); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(4); |
|
||||||
|
|
||||||
MailUtils.sendMails(Arrays.asList(receivers),Arrays.asList(receiversCc),alert.getTitle(),alert.getContent(), ShowType.TEXT.getDescp()); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Test |
|
||||||
public void testQuery(){ |
|
||||||
AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class); |
|
||||||
List<Alert> alerts = alertDao.listWaitExecutionAlert(); |
|
||||||
|
|
||||||
String[] mails = new String[]{"xx@xx.com"}; |
|
||||||
|
|
||||||
for(Alert alert : alerts){ |
|
||||||
MailUtils.sendMails(Arrays.asList(mails),"gaojing", alert.getContent(), ShowType.TABLE.getDescp()); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public String list2String(){ |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map1 = new LinkedHashMap<>(); |
|
||||||
map1.put("mysql service name","mysql200"); |
|
||||||
map1.put("mysql address","192.168.xx.xx"); |
|
||||||
map1.put("port","3306"); |
|
||||||
map1.put("no index of number","80"); |
|
||||||
map1.put("database client connections","190"); |
|
||||||
|
|
||||||
LinkedHashMap<String, Object> map2 = new LinkedHashMap<>(); |
|
||||||
map2.put("mysql service name","mysql210"); |
|
||||||
map2.put("mysql address","192.168.xx.xx"); |
|
||||||
map2.put("port","3306"); |
|
||||||
map2.put("no index of number","10"); |
|
||||||
map2.put("database client connections","90"); |
|
||||||
|
|
||||||
List<LinkedHashMap<String, Object>> maps = new ArrayList<>(); |
|
||||||
maps.add(0,map1); |
|
||||||
maps.add(1,map2); |
|
||||||
String mapjson = JSONUtils.toJsonString(maps); |
|
||||||
logger.info(mapjson); |
|
||||||
|
|
||||||
return mapjson; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testSendTableMail(){ |
|
||||||
String[] mails = new String[]{"347801120@qq.com"}; |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TABLE); |
|
||||||
String content= list2String(); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
MailUtils.sendMails(Arrays.asList(mails),"gaojing", alert.getContent(), ShowType.TABLE.getDescp()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Used to test add alarm information, mail sent |
|
||||||
* Text |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void addAlertText(){ |
|
||||||
AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class); |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TEXT); |
|
||||||
alert.setContent("[\"alarm time:2018-02-05\", \"service name:MYSQL_ALTER\", \"alarm name:MYSQL_ALTER_DUMP\", " + |
|
||||||
"\"get the alarm exception.!,interface error,exception information:timed out\", \"request address:http://blog.csdn.net/dreamInTheWorld/article/details/78539286\"]"); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
alertDao.addAlert(alert); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Used to test add alarm information, mail sent |
|
||||||
* Table |
|
||||||
*/ |
|
||||||
@Test |
|
||||||
public void testAddAlertTable(){ |
|
||||||
logger.info("testAddAlertTable"); |
|
||||||
AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class); |
|
||||||
Assert.assertNotNull(alertDao); |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TABLE); |
|
||||||
|
|
||||||
String content = list2String(); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
alertDao.addAlert(alert); |
|
||||||
logger.info("" +alert); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testAlertDao(){ |
|
||||||
AlertDao alertDao = DaoFactory.getDaoInstance(AlertDao.class); |
|
||||||
List<User> users = alertDao.listUserByAlertgroupId(3); |
|
||||||
logger.info(users.toString()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testAttachmentFile()throws Exception{ |
|
||||||
String[] mails = new String[]{"xx@xx.com"}; |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.ATTACHMENT); |
|
||||||
String content = list2String(); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
MailUtils.sendMails(Arrays.asList(mails),"gaojing",alert.getContent(),ShowType.ATTACHMENT.getDescp()); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testTableAttachmentFile()throws Exception{ |
|
||||||
String[] mails = new String[]{"xx@xx.com"}; |
|
||||||
Alert alert = new Alert(); |
|
||||||
alert.setTitle("Mysql Exception"); |
|
||||||
alert.setShowType(ShowType.TABLEATTACHMENT); |
|
||||||
String content = list2String(); |
|
||||||
alert.setContent(content); |
|
||||||
alert.setAlertType(AlertType.EMAIL); |
|
||||||
alert.setAlertGroupId(1); |
|
||||||
MailUtils.sendMails(Arrays.asList(mails),"gaojing",alert.getContent(),ShowType.TABLEATTACHMENT.getDescp()); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,240 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.api.controller; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.CREATE_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.DELETE_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.GET_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.LIST_PAGING_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_ALL_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.UPDATE_ALERT_PLUGIN_INSTANCE_ERROR; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.exceptions.ApiException; |
||||||
|
import org.apache.dolphinscheduler.api.service.AlertPluginInstanceService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import io.swagger.annotations.Api; |
||||||
|
import io.swagger.annotations.ApiImplicitParam; |
||||||
|
import io.swagger.annotations.ApiImplicitParams; |
||||||
|
import io.swagger.annotations.ApiOperation; |
||||||
|
import springfox.documentation.annotations.ApiIgnore; |
||||||
|
|
||||||
|
/** |
||||||
|
* alert plugin instance controller |
||||||
|
*/ |
||||||
|
@Api(tags = "ALERT_PLUGIN_INSTANCE_TAG", position = 1) |
||||||
|
@RestController |
||||||
|
@RequestMapping("alert-plugin-instance") |
||||||
|
public class AlertPluginInstanceController extends BaseController { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(AlertPluginInstanceController.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private AlertPluginInstanceService alertPluginInstanceService; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* create alert plugin instance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param pluginDefineId alert plugin define id |
||||||
|
* @param instanceName instance name |
||||||
|
* @param pluginInstanceParams instance params |
||||||
|
* @return result |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "createAlertPluginInstance", notes = "CREATE_ALERT_PLUGIN_INSTANCE_NOTES") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "pluginDefineId", value = "ALERT_PLUGIN_DEFINE_ID", required = true, dataType = "Int", example = "100"), |
||||||
|
@ApiImplicitParam(name = "instanceName", value = "ALERT_PLUGIN_INSTANCE_NAME", required = true, dataType = "String", example = "DING TALK"), |
||||||
|
@ApiImplicitParam(name = "pluginInstanceParams", value = "ALERT_PLUGIN_INSTANCE_PARAMS", required = true, dataType = "String", example = "ALERT_PLUGIN_INSTANCE_PARAMS") |
||||||
|
}) |
||||||
|
@PostMapping(value = "/create") |
||||||
|
@ResponseStatus(HttpStatus.CREATED) |
||||||
|
@ApiException(CREATE_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result createAlertPluginInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "pluginDefineId") int pluginDefineId, |
||||||
|
@RequestParam(value = "instanceName") String instanceName, |
||||||
|
@RequestParam(value = "pluginInstanceParams") String pluginInstanceParams) { |
||||||
|
logger.info("login user {},create alert plugin instance, instanceName:{} ", |
||||||
|
StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), |
||||||
|
StringUtils.replaceNRTtoUnderline(instanceName)); |
||||||
|
Map<String, Object> result = alertPluginInstanceService.create(loginUser, pluginDefineId, instanceName, pluginInstanceParams); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updateAlertPluginInstance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param alertPluginInstanceId alert plugin instance id |
||||||
|
* @param instanceName instance name |
||||||
|
* @param pluginInstanceParams instance params |
||||||
|
* @return result |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "update", notes = "UPDATE_ALERT_PLUGIN_INSTANCE_NOTES") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "alertPluginInstanceId", value = "ALERT_PLUGIN_INSTANCE_ID", required = true, dataType = "Int", example = "100"), |
||||||
|
@ApiImplicitParam(name = "instanceName", value = "ALERT_PLUGIN_INSTANCE_NAME", required = true, dataType = "String", example = "DING TALK"), |
||||||
|
@ApiImplicitParam(name = "pluginInstanceParams", value = "ALERT_PLUGIN_INSTANCE_PARAMS", required = true, dataType = "String", example = "ALERT_PLUGIN_INSTANCE_PARAMS") |
||||||
|
}) |
||||||
|
@GetMapping(value = "/update") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
@ApiException(UPDATE_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result updateAlertPluginInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "alertPluginInstanceId") int alertPluginInstanceId, |
||||||
|
@RequestParam(value = "instanceName") String instanceName, |
||||||
|
@RequestParam(value = "pluginInstanceParams") String pluginInstanceParams) { |
||||||
|
logger.info("login user {},update alert plugin instance id {}", StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), alertPluginInstanceId); |
||||||
|
Map<String, Object> result = alertPluginInstanceService.update(loginUser, alertPluginInstanceId, instanceName, pluginInstanceParams); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* deleteAlertPluginInstance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param id id |
||||||
|
* @return result |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "delete", notes = "DELETE_ALERT_PLUGIN_INSTANCE_NOTES") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "id", value = "ALERT_PLUGIN_ID", required = true, dataType = "Int", example = "100") |
||||||
|
}) |
||||||
|
@GetMapping(value = "/delete") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
@ApiException(DELETE_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result deleteAlertPluginInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "id") int id) { |
||||||
|
logger.info("login user {},delete alert plugin instance id {}", StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), id); |
||||||
|
|
||||||
|
Map<String, Object> result = alertPluginInstanceService.delete(loginUser, id); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* getAlertPluginInstance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param id alert plugin instance id |
||||||
|
* @return result |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "get", notes = "GET_ALERT_PLUGIN_INSTANCE_NOTES") |
||||||
|
@PostMapping(value = "/get") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
@ApiException(GET_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result getAlertPluginInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "id") int id) { |
||||||
|
logger.info("login user {},get alert plugin instance, id {}", StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), id); |
||||||
|
Map<String, Object> result = alertPluginInstanceService.get(loginUser, id); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* getAlertPluginInstance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return result |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "/queryAll", notes = "QUERY_ALL_ALERT_PLUGIN_INSTANCE_NOTES") |
||||||
|
@PostMapping(value = "/queryAll") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
@ApiException(QUERY_ALL_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result getAlertPluginInstance(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser) { |
||||||
|
logger.info("login user {}, query all alert plugin instance", StringUtils.replaceNRTtoUnderline(loginUser.getUserName())); |
||||||
|
Map<String, Object> result = alertPluginInstanceService.queryAll(); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check alert group exist |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param alertInstanceName alert instance name |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "verifyAlertInstanceName", notes = "VERIFY_ALERT_INSTANCE_NAME_NOTES") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "groupName", value = "GROUP_NAME", required = true, dataType = "String"), |
||||||
|
}) |
||||||
|
@GetMapping(value = "/verify-alert-instance-name") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
public Result verifyGroupName(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "alertInstanceName") String alertInstanceName) { |
||||||
|
logger.info("login user {},verify alert instance name: {}", StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), StringUtils.replaceNRTtoUnderline(alertInstanceName)); |
||||||
|
|
||||||
|
boolean exist = alertPluginInstanceService.checkExistPluginInstanceName(alertInstanceName); |
||||||
|
Result result = new Result(); |
||||||
|
if (exist) { |
||||||
|
logger.error("alert plugin instance {} has exist, can't create again.", alertInstanceName); |
||||||
|
result.setCode(Status.PLUGIN_INSTANCE_ALREADY_EXIT.getCode()); |
||||||
|
result.setMsg(Status.PLUGIN_INSTANCE_ALREADY_EXIT.getMsg()); |
||||||
|
} else { |
||||||
|
result.setCode(Status.SUCCESS.getCode()); |
||||||
|
result.setMsg(Status.SUCCESS.getMsg()); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* paging query alert plugin instance group list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @return alert plugin instance list page |
||||||
|
*/ |
||||||
|
@ApiOperation(value = "queryAlertPluginInstanceListPaging", notes = "QUERY_ALERT_PLUGIN_INSTANCE_LIST_PAGING_NOTES") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "pageNo", value = "PAGE_NO", dataType = "Int", example = "1"), |
||||||
|
@ApiImplicitParam(name = "pageSize", value = "PAGE_SIZE", dataType = "Int", example = "20") |
||||||
|
}) |
||||||
|
@GetMapping(value = "/list-paging") |
||||||
|
@ResponseStatus(HttpStatus.OK) |
||||||
|
@ApiException(LIST_PAGING_ALERT_PLUGIN_INSTANCE_ERROR) |
||||||
|
public Result listPaging(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam("pageNo") Integer pageNo, |
||||||
|
@RequestParam("pageSize") Integer pageSize) { |
||||||
|
logger.info("login user {}, list paging, pageNo: {}, pageSize: {}",StringUtils.replaceNRTtoUnderline(loginUser.getUserName()), pageNo, pageSize); |
||||||
|
Map<String, Object> result = checkPageParams(pageNo, pageSize); |
||||||
|
if (result.get(Constants.STATUS) != Status.SUCCESS) { |
||||||
|
return returnDataListPaging(result); |
||||||
|
} |
||||||
|
|
||||||
|
result = alertPluginInstanceService.queryPluginPage(pageNo, pageSize); |
||||||
|
return returnDataListPaging(result); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
/* |
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||||
|
* contributor license agreements. See the NOTICE file distributed with |
||||||
|
* this work for additional information regarding copyright ownership. |
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||||
|
* (the "License"); you may not use this file except in compliance with |
||||||
|
* the License. You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package org.apache.dolphinscheduler.api.controller; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.api.enums.Status.QUERY_PLUGINS_ERROR; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.exceptions.ApiException; |
||||||
|
import org.apache.dolphinscheduler.api.service.UiPluginService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.PluginType; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestAttribute; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import io.swagger.annotations.Api; |
||||||
|
import io.swagger.annotations.ApiImplicitParam; |
||||||
|
import io.swagger.annotations.ApiImplicitParams; |
||||||
|
import io.swagger.annotations.ApiOperation; |
||||||
|
import springfox.documentation.annotations.ApiIgnore; |
||||||
|
|
||||||
|
/** |
||||||
|
* UiPluginController |
||||||
|
* Some plugins (such as alert plugin) need to provide UI interfaces to users. |
||||||
|
* We use from-creat to dynamically generate UI interfaces. Related parameters are mainly provided by pluginParams. |
||||||
|
* From-create can generate dynamic ui based on this parameter. |
||||||
|
*/ |
||||||
|
@Api(tags = "UI_PLUGINS", position = 1) |
||||||
|
@RestController |
||||||
|
@RequestMapping("ui-plugins") |
||||||
|
public class UiPluginController extends BaseController { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(UiPluginController.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
UiPluginService uiPluginService; |
||||||
|
|
||||||
|
@ApiOperation(value = "queryUiPluginsByType", notes = "QUERY_UI_PLUGINS_BY_TYPE") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "pluginType", value = "pluginType", required = true, dataType = "PluginType"), |
||||||
|
}) |
||||||
|
@PostMapping(value = "/queryUiPluginsByType") |
||||||
|
@ResponseStatus(HttpStatus.CREATED) |
||||||
|
@ApiException(QUERY_PLUGINS_ERROR) |
||||||
|
public Result queryUiPluginsByType(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam(value = "pluginType") PluginType pluginType) { |
||||||
|
|
||||||
|
logger.info("query plugins by type , pluginType: {}", pluginType); |
||||||
|
Map<String, Object> result = uiPluginService.queryUiPluginsByType(pluginType); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
|
||||||
|
@ApiOperation(value = "queryUiPluginDetailById", notes = "QUERY_UI_PLUGIN_DETAIL_BY_ID") |
||||||
|
@ApiImplicitParams({ |
||||||
|
@ApiImplicitParam(name = "id", value = "id", required = true, dataType = "PluginType"), |
||||||
|
}) |
||||||
|
@PostMapping(value = "/queryUiPluginDetailById") |
||||||
|
@ResponseStatus(HttpStatus.CREATED) |
||||||
|
@ApiException(QUERY_PLUGINS_ERROR) |
||||||
|
public Result queryUiPluginDetailById(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser, |
||||||
|
@RequestParam("pluginId") Integer pluginId) { |
||||||
|
|
||||||
|
logger.info("query plugin detail by id , pluginId: {}", pluginId); |
||||||
|
Map<String, Object> result = uiPluginService.queryUiPluginDetailById(pluginId); |
||||||
|
return returnDataList(result); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue