15
15
*/
16
16
package io .cdap .cdap .master .upgrade ;
17
17
18
+ import com .google .common .reflect .TypeToken ;
19
+ import com .google .gson .Gson ;
20
+ import com .google .gson .JsonObject ;
18
21
import io .cdap .cdap .api .retry .RetryableException ;
19
22
import io .cdap .cdap .client .ApplicationClient ;
20
23
import io .cdap .cdap .client .NamespaceClient ;
39
42
import io .cdap .cdap .proto .id .WorkflowId ;
40
43
import io .cdap .cdap .security .impersonation .SecurityUtil ;
41
44
import java .io .IOException ;
45
+ import java .lang .reflect .Type ;
42
46
import java .util .List ;
43
47
import java .util .concurrent .TimeUnit ;
44
48
import java .util .stream .Collectors ;
54
58
public class UpgradeJobMain {
55
59
56
60
private static final int DEFAULT_READ_TIMEOUT_MILLIS = 90 * 1000 ;
61
+ private static final int APP_LIST_PAGE_SIZE = 25 ;
57
62
private static final String SCHEDULED = "SCHEDULED" ;
58
63
private static final Logger LOG = LoggerFactory .getLogger (UpgradeJobMain .class );
59
64
65
+ private static final Gson GSON = new Gson ();
66
+
60
67
public static void main (String [] args ) {
61
68
if (args .length != 2 ) {
62
69
throw new RuntimeException (
@@ -72,7 +79,8 @@ public static void main(String[] args) {
72
79
ClientConfig .Builder clientConfigBuilder =
73
80
ClientConfig .builder ()
74
81
.setDefaultReadTimeout (DEFAULT_READ_TIMEOUT_MILLIS )
75
- .setConnectionConfig (connectionConfig );
82
+ .setConnectionConfig (connectionConfig )
83
+ .setAppListPageSize (APP_LIST_PAGE_SIZE );
76
84
77
85
// If used in proxy mode, attach a user ID header to upgrade jobs.
78
86
CConfiguration cConf = CConfiguration .create ();
@@ -114,43 +122,62 @@ private static void suspendSchedulesAndStopPipelines(ClientConfig clientConfig)
114
122
namespaceIdList .add (NamespaceId .SYSTEM );
115
123
116
124
for (NamespaceId namespaceId : namespaceIdList ) {
117
- for (ApplicationRecord record : applicationClient .list (namespaceId )) {
118
- ApplicationId applicationId =
119
- new ApplicationId (namespaceId .getNamespace (), record .getName (), record .getAppVersion ());
120
- LOG .debug ("Trying to stop schedule and workflows for application " + applicationId );
121
- List <WorkflowId > workflowIds =
122
- applicationClient .get (applicationId ).getPrograms ().stream ()
123
- .filter (programRecord -> programRecord .getType ().equals (ProgramType .WORKFLOW ))
124
- .map (programRecord -> new WorkflowId (applicationId , programRecord .getName ()))
125
- .collect (Collectors .toList ());
126
- for (WorkflowId workflowId : workflowIds ) {
127
- List <ScheduleId > scheduleIds =
128
- scheduleClient .listSchedules (workflowId ).stream ()
129
- .map (scheduleDetail ->
130
- new ScheduleId (namespaceId .getNamespace (), record .getName (),
131
- scheduleDetail .getName ()))
132
- .collect (Collectors .toList ());
133
- for (ScheduleId scheduleId : scheduleIds ) {
134
- if (scheduleClient .getStatus (scheduleId ).equals (SCHEDULED )) {
135
- scheduleClient .suspend (scheduleId );
136
- }
137
- }
138
- // Need to stop workflows first or else the program will fail to stop below
139
- if (!programClient .getStatus (workflowId ).equals (ProgramStatus .STOPPED .toString ())) {
140
- try {
141
- programClient .stop (workflowId );
142
- } catch (BadRequestException e ) {
143
- // There might be race condition between checking if the program is in RUNNING state and stopping it.
144
- // This can cause programClient.stop to throw BadRequestException so verifying if the program
145
- // transitioned to stop state since it was checked earlier or not.
125
+ String token = null ;
126
+ boolean isLastPage = false ;
127
+ while (!isLastPage ) {
128
+ JsonObject paginatedListResponse = applicationClient .paginatedList (namespaceId , token );
129
+ token = paginatedListResponse .get ("nextPageToken" ) == null ? null
130
+ : paginatedListResponse .get ("nextPageToken" ).getAsString ();
131
+ LOG .debug ("Called paginated list API and got token: {}" , token );
132
+ if (paginatedListResponse .get ("applications" ).getAsJsonArray ().size () != 0 ) {
133
+ Type appListType = new TypeToken <List <ApplicationRecord >>() {
134
+ }.getType ();
135
+ List <ApplicationRecord > records = GSON .fromJson (
136
+ paginatedListResponse .get ("applications" ).getAsJsonArray (), appListType );
137
+ for (ApplicationRecord record : records ) {
138
+ ApplicationId applicationId =
139
+ new ApplicationId (namespaceId .getNamespace (),
140
+ record .getName (), record .getAppVersion ());
141
+ LOG .debug ("Trying to stop schedule and workflows for application " + applicationId );
142
+ List <WorkflowId > workflowIds =
143
+ applicationClient .get (applicationId ).getPrograms ().stream ()
144
+ .filter (programRecord -> programRecord .getType ().equals (ProgramType .WORKFLOW ))
145
+ .map (programRecord -> new WorkflowId (applicationId , programRecord .getName ()))
146
+ .collect (Collectors .toList ());
147
+ for (WorkflowId workflowId : workflowIds ) {
148
+ List <ScheduleId > scheduleIds =
149
+ scheduleClient .listSchedules (workflowId ).stream ()
150
+ .map (scheduleDetail ->
151
+ new ScheduleId (namespaceId .getNamespace (), record .getName (),
152
+ scheduleDetail .getName ()))
153
+ .collect (Collectors .toList ());
154
+ for (ScheduleId scheduleId : scheduleIds ) {
155
+ if (scheduleClient .getStatus (scheduleId ).equals (SCHEDULED )) {
156
+ scheduleClient .suspend (scheduleId );
157
+ }
158
+ }
159
+ // Need to stop workflows first or else the program will fail to stop below
146
160
if (!programClient .getStatus (workflowId ).equals (ProgramStatus .STOPPED .toString ())) {
147
- // Pipeline still in running state. Continue with stopping rest of the pipelines in this namespace and
148
- // next retry should try to stop/verify status for this pipeline.
149
- shouldRetry = true ;
161
+ try {
162
+ programClient .stop (workflowId );
163
+ } catch (BadRequestException e ) {
164
+ // There might be race condition between checking if the program
165
+ // is in RUNNING state and stopping it. This can cause programClient.stop to
166
+ // throw BadRequestException so verifying if the program transitioned to stop
167
+ // state since it was checked earlier or not.
168
+ if (!programClient .getStatus (workflowId )
169
+ .equals (ProgramStatus .STOPPED .toString ())) {
170
+ // Pipeline still in running state. Continue with stopping rest of the
171
+ // pipelines in this namespace and next retry should try to stop/verify status
172
+ // for this pipeline.
173
+ shouldRetry = true ;
174
+ }
175
+ }
150
176
}
151
177
}
152
178
}
153
179
}
180
+ isLastPage = (token == null );
154
181
}
155
182
// At least one pipeline is still in running state so retry to verify pipeline status .
156
183
if (shouldRetry ) {
0 commit comments