11package  org.opensearch.commons.alerting.model 
22
33import  org.apache.logging.log4j.LogManager 
4+ import  org.opensearch.common.unit.TimeValue 
45import  org.opensearch.commons.alerting.model.Monitor.Companion.SCHEMA_VERSION_FIELD 
56import  org.opensearch.commons.alerting.model.MonitorV2.Companion.ENABLED_FIELD 
67import  org.opensearch.commons.alerting.model.MonitorV2.Companion.ENABLED_TIME_FIELD 
78import  org.opensearch.commons.alerting.model.MonitorV2.Companion.LAST_UPDATE_TIME_FIELD 
9+ import  org.opensearch.commons.alerting.model.MonitorV2.Companion.LOOK_BACK_WINDOW_FIELD 
810import  org.opensearch.commons.alerting.model.MonitorV2.Companion.MONITOR_TYPE_FIELD 
911import  org.opensearch.commons.alerting.model.MonitorV2.Companion.MONITOR_V2_TYPE 
1012import  org.opensearch.commons.alerting.model.MonitorV2.Companion.NAME_FIELD 
@@ -42,8 +44,9 @@ data class PPLMonitor(
4244    override  val  schedule :  Schedule ,
4345    override  val  lastUpdateTime :  Instant ,
4446    override  val  enabledTime :  Instant ? ,
45-     override  val  schemaVersion :  Int  = NO_SCHEMA_VERSION ,
4647    override  val  triggers :  List <TriggerV2 >,
48+     override  val  schemaVersion :  Int  = NO_SCHEMA_VERSION ,
49+     override  val  lookBackWindow :  TimeValue ?  = null ,
4750    val  queryLanguage :  QueryLanguage  = QueryLanguage .PPL , //  default to PPL, SQL not currently supported
4851    val  query :  String 
4952) : MonitorV2 {
@@ -87,8 +90,9 @@ data class PPLMonitor(
8790        schedule =  Schedule .readFrom(sin),
8891        lastUpdateTime =  sin.readInstant(),
8992        enabledTime =  sin.readOptionalInstant(),
90-         schemaVersion =  sin.readInt(),
9193        triggers =  sin.readList(TriggerV2 ::readFrom),
94+         schemaVersion =  sin.readInt(),
95+         lookBackWindow =  TimeValue .parseTimeValue(sin.readString(), PLACEHOLDER_LOOK_BACK_WINDOW_SETTING_NAME ),
9296        queryLanguage =  sin.readEnum(QueryLanguage ::class .java),
9397        query =  sin.readString()
9498    )
@@ -112,8 +116,9 @@ data class PPLMonitor(
112116        builder.field(ENABLED_FIELD , enabled)
113117        builder.nonOptionalTimeField(LAST_UPDATE_TIME_FIELD , lastUpdateTime)
114118        builder.optionalTimeField(ENABLED_TIME_FIELD , enabledTime)
115-         builder.field(SCHEMA_VERSION_FIELD , schemaVersion)
116119        builder.field(TRIGGERS_FIELD , triggers.toTypedArray())
120+         builder.field(SCHEMA_VERSION_FIELD , schemaVersion)
121+         builder.field(LOOK_BACK_WINDOW_FIELD , lookBackWindow?.toHumanReadableString(0 ))
117122        builder.field(QUERY_LANGUAGE_FIELD , queryLanguage.value)
118123        builder.field(QUERY_FIELD , query)
119124
@@ -142,12 +147,16 @@ data class PPLMonitor(
142147        }
143148        out .writeInstant(lastUpdateTime)
144149        out .writeOptionalInstant(enabledTime)
145-         out .writeInt(schemaVersion)
146150        out .writeVInt(triggers.size)
147151        triggers.forEach {
148152            out .writeEnum(TriggerV2 .TriggerV2Type .PPL_TRIGGER )
149153            it.writeTo(out )
150154        }
155+         out .writeInt(schemaVersion)
156+ 
157+         out .writeBoolean(lookBackWindow !=  null )
158+         lookBackWindow?.let  { out .writeString(lookBackWindow.toHumanReadableString(0 )) }
159+ 
151160        out .writeEnum(queryLanguage)
152161        out .writeString(query)
153162    }
@@ -162,6 +171,7 @@ data class PPLMonitor(
162171            LAST_UPDATE_TIME_FIELD  to lastUpdateTime.toEpochMilli(),
163172            ENABLED_TIME_FIELD  to enabledTime?.toEpochMilli(),
164173            TRIGGERS_FIELD  to triggers,
174+             LOOK_BACK_WINDOW_FIELD  to lookBackWindow?.toHumanReadableString(0 ),
165175            QUERY_LANGUAGE_FIELD  to queryLanguage.value,
166176            QUERY_FIELD  to query
167177        )
@@ -188,6 +198,11 @@ data class PPLMonitor(
188198        const  val  QUERY_LANGUAGE_FIELD  =  " query_language" 
189199        const  val  QUERY_FIELD  =  " query" 
190200
201+         //  mock setting name used when parsing TimeValue
202+         //  TimeValue class is usually reserved for declaring settings, but we're using it
203+         //  outside that use case here, which is why we need these placeholders
204+         private  const  val  PLACEHOLDER_LOOK_BACK_WINDOW_SETTING_NAME  =  " ppl_monitor_look_back_window" 
205+ 
191206        @JvmStatic
192207        @JvmOverloads
193208        @Throws(IOException ::class )
@@ -198,8 +213,9 @@ data class PPLMonitor(
198213            var  schedule:  Schedule ?  =  null 
199214            var  lastUpdateTime:  Instant ?  =  null 
200215            var  enabledTime:  Instant ?  =  null 
201-             var  schemaVersion =  NO_SCHEMA_VERSION 
202216            val  triggers:  MutableList <TriggerV2 > =  mutableListOf ()
217+             var  schemaVersion =  NO_SCHEMA_VERSION 
218+             var  lookBackWindow:  TimeValue ?  =  null 
203219            var  queryLanguage:  QueryLanguage  =  QueryLanguage .PPL  //  default to PPL
204220            var  query:  String?  =  null 
205221
@@ -216,7 +232,6 @@ data class PPLMonitor(
216232                    SCHEDULE_FIELD  ->  schedule =  Schedule .parse(xcp)
217233                    LAST_UPDATE_TIME_FIELD  ->  lastUpdateTime =  xcp.instant()
218234                    ENABLED_TIME_FIELD  ->  enabledTime =  xcp.instant()
219-                     SCHEMA_VERSION_FIELD  ->  schemaVersion =  xcp.intValue()
220235                    TRIGGERS_FIELD  ->  {
221236                        XContentParserUtils .ensureExpectedToken(
222237                            XContentParser .Token .START_ARRAY ,
@@ -227,6 +242,15 @@ data class PPLMonitor(
227242                            triggers.add(PPLTrigger .parseInner(xcp))
228243                        }
229244                    }
245+                     SCHEMA_VERSION_FIELD  ->  schemaVersion =  xcp.intValue()
246+                     LOOK_BACK_WINDOW_FIELD  ->  {
247+                         lookBackWindow =  if  (xcp.currentToken() ==  XContentParser .Token .VALUE_NULL ) {
248+                             null 
249+                         } else  {
250+                             val  input =  xcp.text()
251+                             TimeValue .parseTimeValue(input, PLACEHOLDER_LOOK_BACK_WINDOW_SETTING_NAME ) //  throws IllegalArgumentException if there's parsing error
252+                         }
253+                     }
230254                    QUERY_LANGUAGE_FIELD  ->  {
231255                        val  input =  xcp.text()
232256                        val  enumMatchResult =  QueryLanguage .enumFromString(input)
@@ -269,6 +293,10 @@ data class PPLMonitor(
269293            requireNotNull(query) { " Query is null" 
270294            requireNotNull(lastUpdateTime) { " Last update time is null" 
271295
296+             if  (schedule is  IntervalSchedule  &&  lookBackWindow !=  null ) {
297+                 throw  IllegalArgumentException (" Look back windows only supported for CRON schedules" 
298+             }
299+ 
272300            if  (queryLanguage ==  QueryLanguage .SQL ) {
273301                throw  IllegalArgumentException (" SQL queries are not supported. Please use a PPL query." 
274302            }
@@ -282,8 +310,9 @@ data class PPLMonitor(
282310                schedule,
283311                lastUpdateTime,
284312                enabledTime,
285-                 schemaVersion,
286313                triggers,
314+                 schemaVersion,
315+                 lookBackWindow,
287316                queryLanguage,
288317                query
289318            )
0 commit comments