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