5
5
*/
6
6
package org .elasticsearch .xpack .watcher .notification .email .attachment ;
7
7
8
+ import com .google .common .collect .ImmutableMap ;
8
9
import org .apache .logging .log4j .LogManager ;
9
10
import org .apache .logging .log4j .Logger ;
11
+ import org .apache .logging .log4j .message .ParameterizedMessage ;
10
12
import org .elasticsearch .ElasticsearchException ;
11
13
import org .elasticsearch .common .ParseField ;
12
14
import org .elasticsearch .common .Strings ;
13
15
import org .elasticsearch .common .bytes .BytesReference ;
14
16
import org .elasticsearch .common .logging .LoggerMessageFormat ;
17
+ import org .elasticsearch .common .settings .ClusterSettings ;
15
18
import org .elasticsearch .common .settings .Setting ;
16
19
import org .elasticsearch .common .settings .Settings ;
17
20
import org .elasticsearch .common .unit .TimeValue ;
37
40
import java .io .IOException ;
38
41
import java .io .InputStream ;
39
42
import java .io .UncheckedIOException ;
43
+ import java .util .ArrayList ;
44
+ import java .util .Arrays ;
45
+ import java .util .HashSet ;
46
+ import java .util .List ;
47
+ import java .util .Locale ;
40
48
import java .util .Map ;
49
+ import java .util .Set ;
50
+ import java .util .concurrent .ConcurrentHashMap ;
41
51
42
52
public class ReportingAttachmentParser implements EmailAttachmentParser <ReportingAttachment > {
43
53
44
54
public static final String TYPE = "reporting" ;
45
55
46
56
// total polling of 10 minutes happens this way by default
47
- public static final Setting <TimeValue > INTERVAL_SETTING =
57
+ static final Setting <TimeValue > INTERVAL_SETTING =
48
58
Setting .timeSetting ("xpack.notification.reporting.interval" , TimeValue .timeValueSeconds (15 ), Setting .Property .NodeScope );
49
- public static final Setting <Integer > RETRIES_SETTING =
59
+ static final Setting <Integer > RETRIES_SETTING =
50
60
Setting .intSetting ("xpack.notification.reporting.retries" , 40 , 0 , Setting .Property .NodeScope );
51
61
62
+ static final Setting <Boolean > REPORT_WARNING_ENABLED_SETTING =
63
+ Setting .boolSetting ("xpack.notification.reporting.warning.enabled" , true , Setting .Property .NodeScope , Setting .Property .Dynamic );
64
+
65
+ static final Setting .AffixSetting <String > REPORT_WARNING_TEXT =
66
+ Setting .affixKeySetting ("xpack.notification.reporting.warning." , "text" ,
67
+ key -> Setting .simpleString (key , Setting .Property .NodeScope , Setting .Property .Dynamic ));
68
+
52
69
private static final ObjectParser <Builder , AuthParseContext > PARSER = new ObjectParser <>("reporting_attachment" );
53
70
private static final ObjectParser <KibanaReportingPayload , Void > PAYLOAD_PARSER =
54
71
new ObjectParser <>("reporting_attachment_kibana_payload" , true , null );
55
72
73
+ static final Map <String , String > WARNINGS = ImmutableMap .of ("kbn-csv-contains-formulas" , "Warning: The attachment [%s] contains " +
74
+ "characters which spreadsheet applications may interpret as formulas. Please ensure that the attachment is safe prior to opening." );
75
+
56
76
static {
57
77
PARSER .declareInt (Builder ::retries , ReportingAttachment .RETRIES );
58
78
PARSER .declareBoolean (Builder ::inline , ReportingAttachment .INLINE );
@@ -63,18 +83,52 @@ public class ReportingAttachmentParser implements EmailAttachmentParser<Reportin
63
83
PAYLOAD_PARSER .declareString (KibanaReportingPayload ::setPath , new ParseField ("path" ));
64
84
}
65
85
86
+ private static List <Setting <?>> getDynamicSettings () {
87
+ return Arrays .asList (REPORT_WARNING_ENABLED_SETTING , REPORT_WARNING_TEXT );
88
+ }
89
+
90
+ private static List <Setting <?>> getStaticSettings () {
91
+ return Arrays .asList (INTERVAL_SETTING , RETRIES_SETTING );
92
+ }
93
+
94
+ public static List <Setting <?>> getSettings () {
95
+ List <Setting <?>> allSettings = new ArrayList <Setting <?>>(getDynamicSettings ());
96
+ allSettings .addAll (getStaticSettings ());
97
+ return allSettings ;
98
+ }
66
99
private final Logger logger ;
67
100
private final TimeValue interval ;
68
101
private final int retries ;
69
102
private HttpClient httpClient ;
70
103
private final TextTemplateEngine templateEngine ;
104
+ private boolean warningEnabled = REPORT_WARNING_ENABLED_SETTING .getDefault (Settings .EMPTY );
105
+ private final Map <String , String > customWarnings = new ConcurrentHashMap <>(1 );
71
106
72
- public ReportingAttachmentParser (Settings settings , HttpClient httpClient , TextTemplateEngine templateEngine ) {
107
+ public ReportingAttachmentParser (Settings settings , HttpClient httpClient , TextTemplateEngine templateEngine ,
108
+ ClusterSettings clusterSettings ) {
73
109
this .interval = INTERVAL_SETTING .get (settings );
74
110
this .retries = RETRIES_SETTING .get (settings );
75
111
this .httpClient = httpClient ;
76
112
this .templateEngine = templateEngine ;
77
113
this .logger = LogManager .getLogger (getClass ());
114
+ clusterSettings .addSettingsUpdateConsumer (REPORT_WARNING_ENABLED_SETTING , this ::setWarningEnabled );
115
+ clusterSettings .addAffixUpdateConsumer (REPORT_WARNING_TEXT , this ::addWarningText , this ::warningValidator );
116
+ }
117
+
118
+ void setWarningEnabled (boolean warningEnabled ) {
119
+ this .warningEnabled = warningEnabled ;
120
+ }
121
+
122
+ void addWarningText (String name , String value ) {
123
+ customWarnings .put (name , value );
124
+ }
125
+
126
+ void warningValidator (String name , String value ) {
127
+ if (WARNINGS .keySet ().contains (name ) == false ) {
128
+ throw new IllegalArgumentException (new ParameterizedMessage (
129
+ "Warning [{}] is not supported. Only the following warnings are supported [{}]" ,
130
+ name , String .join (", " , WARNINGS .keySet ())).getFormattedMessage ());
131
+ }
78
132
}
79
133
80
134
@ Override
@@ -139,8 +193,24 @@ public Attachment toAttachment(WatchExecutionContext context, Payload payload, R
139
193
"method[{}], path[{}], status[{}], body[{}]" , context .watch ().id (), attachment .id (), request .host (),
140
194
request .port (), request .method (), request .path (), response .status (), body );
141
195
} else if (response .status () == 200 ) {
142
- return new Attachment .Bytes (attachment .id (), BytesReference .toBytes (response .body ()),
143
- response .contentType (), attachment .inline ());
196
+ Set <String > warnings = new HashSet <>(1 );
197
+ if (warningEnabled ) {
198
+ WARNINGS .forEach ((warningKey , defaultWarning ) -> {
199
+ String [] text = response .header (warningKey );
200
+ if (text != null && text .length > 0 ) {
201
+ if (Boolean .valueOf (text [0 ])) {
202
+ String warning = String .format (Locale .ROOT , defaultWarning , attachment .id ());
203
+ String customWarning = customWarnings .get (warningKey );
204
+ if (Strings .isNullOrEmpty (customWarning ) == false ) {
205
+ warning = String .format (Locale .ROOT , customWarning , attachment .id ());
206
+ }
207
+ warnings .add (warning );
208
+ }
209
+ }
210
+ });
211
+ }
212
+ return new Attachment .Bytes (attachment .id (), attachment .id (), BytesReference .toBytes (response .body ()),
213
+ response .contentType (), attachment .inline (), warnings );
144
214
} else {
145
215
String body = response .body () != null ? response .body ().utf8ToString () : null ;
146
216
String message = LoggerMessageFormat .format ("" , "Watch[{}] reporting[{}] Unexpected status code host[{}], port[{}], " +
0 commit comments