You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aurora.apache.org by dm...@apache.org on 2017/10/18 23:21:45 UTC

aurora git commit: Add cron configuration to Job Page

Repository: aurora
Updated Branches:
  refs/heads/master 4f52f754f -> c6388774b


Add cron configuration to Job Page

Reviewed at https://reviews.apache.org/r/63125/


Project: http://git-wip-us.apache.org/repos/asf/aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/c6388774
Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/c6388774
Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/c6388774

Branch: refs/heads/master
Commit: c6388774ba2eef7bed18668c8c735d6134d22e80
Parents: 4f52f75
Author: David McLaughlin <da...@dmclaughlin.com>
Authored: Wed Oct 18 16:16:21 2017 -0700
Committer: David McLaughlin <da...@dmclaughlin.com>
Committed: Wed Oct 18 16:16:21 2017 -0700

----------------------------------------------------------------------
 ui/.eslintrc                                    |   1 +
 ui/src/main/js/components/JobConfig.js          |  18 ++-
 ui/src/main/js/components/TaskConfigSummary.js  | 110 +++++++++++++++----
 .../js/components/__tests__/JobConfig-test.js   |  11 +-
 ui/src/main/js/pages/Job.js                     |  23 +++-
 ui/src/main/js/pages/__tests__/Job-test.js      |   3 +-
 ui/src/main/js/utils/Thrift.js                  |   1 +
 ui/src/main/sass/components/_job-page.scss      |   4 +
 ui/test-setup.js                                |   6 +
 9 files changed, 144 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/.eslintrc
----------------------------------------------------------------------
diff --git a/ui/.eslintrc b/ui/.eslintrc
index f7ac075..5cdc4e6 100644
--- a/ui/.eslintrc
+++ b/ui/.eslintrc
@@ -11,6 +11,7 @@
   "globals": {
     "ACTIVE_STATES": true,
     "ACTIVE_JOB_UPDATE_STATES": true,
+    "CronCollisionPolicy": true,
     "JobKey": true,
     "JobUpdateAction": true,
     "JobUpdateKey": true,

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/components/JobConfig.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/components/JobConfig.js b/ui/src/main/js/components/JobConfig.js
index 275f46a..0bce57c 100644
--- a/ui/src/main/js/components/JobConfig.js
+++ b/ui/src/main/js/components/JobConfig.js
@@ -2,15 +2,27 @@ import React from 'react';
 
 import ConfigDiff from 'components/ConfigDiff';
 import Loading from 'components/Loading';
-import TaskConfigSummary from 'components/TaskConfigSummary';
+import TaskConfigSummary, { CronConfigSummary } from 'components/TaskConfigSummary';
 
 import { isNully, sort } from 'utils/Common';
 
-export default function JobConfig({ groups }) {
-  if (isNully(groups)) {
+export function CronJobConfig({ cronJob }) {
+  return (<div className='job-configuration'>
+    <div className='job-configuration-summaries'>
+      <CronConfigSummary cronJob={cronJob} />
+    </div>
+  </div>);
+}
+
+export default function JobConfig({ cronJob, groups }) {
+  if (isNully(groups) && isNully(cronJob)) {
     return <Loading />;
   }
 
+  if (!isNully(cronJob)) {
+    return <CronJobConfig cronJob={cronJob} />;
+  }
+
   const sorted = sort(groups, (g) => g.instances[0].first);
   return (<div className='job-configuration'>
     <div className='job-configuration-summaries'>

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/components/TaskConfigSummary.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/components/TaskConfigSummary.js b/ui/src/main/js/components/TaskConfigSummary.js
index 5c00d1e..2a325d9 100644
--- a/ui/src/main/js/components/TaskConfigSummary.js
+++ b/ui/src/main/js/components/TaskConfigSummary.js
@@ -1,40 +1,107 @@
+import moment from 'moment';
 import React from 'react';
 
+import { RelativeTime } from 'components/Time';
+
 import { constraintToString, getResource, getResources, instanceRangeToString } from 'utils/Task';
+import { COLLISION_POLICY } from 'utils/Thrift';
 
-export default function TaskConfigSummary({ config, instances }) {
-  return (<table className='table table-bordered task-config-summary'>
+// ESLint doesn't like React's new adjacent elements, so we need to disable it here
+/* eslint-disable */
+function Resources({ config }) {
+  return [<tr>
+    <th rowSpan='4'>Resources</th>
+    <td>cpus</td>
+    <td>{getResource(config.resources, 'numCpus').numCpus}</td>
+  </tr>,
+  <tr>
+    <td>ram</td>
+    <td>{getResource(config.resources, 'ramMb').ramMb}</td>
+  </tr>,
+  <tr>
+    <td>disk</td>
+    <td>{getResource(config.resources, 'diskMb').diskMb}</td>
+  </tr>,
+  <tr>
+    <td>ports</td>
+    <td>{getResources(config.resources, 'namedPort').map((r) => r.namedPort).join(', ')}</td>
+  </tr>];
+}
+/* eslint-enable */
+
+function Constraints({ config }) {
+  return (<tr>
+    <th>Constraints</th>
+    <td colSpan='2'>
+      {config.constraints.map((t) => (<span className='task-constraint' key={t.name}>
+        {t.name}: {constraintToString(t.constraint)}
+      </span>))}
+    </td>
+  </tr>);
+}
+
+function Metadata({ config }) {
+  return (<tr>
+    <th>Metadata</th>
+    <td colSpan='2'>
+      {config.metadata.map((m, i) => <span key={`${m.key}-${i}`}>{m.key}: {m.value}</span>)}
+    </td>
+  </tr>);
+}
+
+export function CronConfigSummary({ cronJob }) {
+  const config = cronJob.job.taskConfig;
+  return (<table className='table table-bordered task-config-summary cron-config-summary'>
     <tbody>
       <tr>
         <th colSpan='100%'>
-          Configuration for instance {instanceRangeToString(instances)}
+          Cron Job Configuration
         </th>
       </tr>
       <tr>
-        <th rowSpan='4'>Resources</th>
-        <td>cpus</td>
-        <td>{getResource(config.resources, 'numCpus').numCpus}</td>
+        <th>Cron Schedule</th>
+        <td colSpan='2'>{cronJob.job.cronSchedule}</td>
       </tr>
       <tr>
-        <td>ram</td>
-        <td>{getResource(config.resources, 'ramMb').ramMb}</td>
+        <th>Collision Policy</th>
+        <td colSpan='2'>{COLLISION_POLICY[cronJob.job.cronCollisionPolicy]}</td>
       </tr>
       <tr>
-        <td>disk</td>
-        <td>{getResource(config.resources, 'diskMb').diskMb}</td>
+        <th>Next Cron Run</th>
+        <td colSpan='2'>
+          {moment(cronJob.nextCronRunMs).format('MMMM Do YYYY, h:mm:ss a')} UTC (
+          <RelativeTime ts={cronJob.nextCronRunMs} />)
+        </td>
       </tr>
       <tr>
-        <td>ports</td>
-        <td>{getResources(config.resources, 'namedPort').map((r) => r.namedPort).join(', ')}</td>
+        <th># Instances</th>
+        <td colSpan='2'>{cronJob.job.instanceCount}</td>
       </tr>
+      <Resources config={config} />
+      <Constraints config={config} />
       <tr>
-        <th>Constraints</th>
-        <td colSpan='2'>
-          {config.constraints.map((t) => (<span className='task-constraint' key={t.name}>
-            {t.name}: {constraintToString(t.constraint)}
-          </span>))}
-        </td>
+        <th>Tier</th>
+        <td colSpan='2'>{config.tier}</td>
+      </tr>
+      <Metadata config={config} />
+      <tr>
+        <th>Contact</th>
+        <td colSpan='2'>{config.contactEmail}</td>
+      </tr>
+    </tbody>
+  </table>);
+}
+
+export default function TaskConfigSummary({ config, instances }) {
+  return (<table className='table table-bordered task-config-summary'>
+    <tbody>
+      <tr>
+        <th colSpan='100%'>
+          Configuration for instance {instanceRangeToString(instances)}
+        </th>
       </tr>
+      <Resources config={config} />
+      <Constraints config={config} />
       <tr>
         <th>Tier</th>
         <td colSpan='2'>{config.tier}</td>
@@ -43,12 +110,7 @@ export default function TaskConfigSummary({ config, instances }) {
         <th>Service</th>
         <td colSpan='2'>{config.isService ? 'true' : 'false'}</td>
       </tr>
-      <tr>
-        <th>Metadata</th>
-        <td colSpan='2'>
-          {config.metadata.map((m, i) => <span key={`${m.key}-${i}`}>{m.key}: {m.value}</span>)}
-        </td>
-      </tr>
+      <Metadata config={config} />
       <tr>
         <th>Contact</th>
         <td colSpan='2'>{config.contactEmail}</td>

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/components/__tests__/JobConfig-test.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/components/__tests__/JobConfig-test.js b/ui/src/main/js/components/__tests__/JobConfig-test.js
index 59541d9..cd1b7a0 100644
--- a/ui/src/main/js/components/__tests__/JobConfig-test.js
+++ b/ui/src/main/js/components/__tests__/JobConfig-test.js
@@ -2,10 +2,11 @@ import React from 'react';
 import { shallow } from 'enzyme';
 
 import ConfigDiff from '../ConfigDiff';
-import JobConfig from '../JobConfig';
+import JobConfig, { CronJobConfig } from '../JobConfig';
 import Loading from '../Loading';
 import TaskConfigSummary from '../TaskConfigSummary';
 
+import { JobSummaryBuilder } from 'test-utils/JobBuilders';
 import { TaskConfigBuilder, createConfigGroup } from 'test-utils/TaskBuilders';
 
 describe('JobConfig', () => {
@@ -20,8 +21,14 @@ describe('JobConfig', () => {
     expect(el.contains(<ConfigDiff groups={[group0, group1, group2]} />)).toBe(true);
   });
 
-  it('Should render Loading when no groups are supplied', () => {
+  it('Should render Loading when no groups or cronJob are supplied', () => {
     const el = shallow(<JobConfig />);
     expect(el.contains(<Loading />)).toBe(true);
   });
+
+  it('Should render CronJobConfig when cronJob is supplied', () => {
+    const cron = JobSummaryBuilder.build();
+    const el = shallow(<JobConfig cronJob={cron} />);
+    expect(el.contains(<CronJobConfig cronJob={cron} />)).toBe(true);
+  });
 });

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/pages/Job.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/pages/Job.js b/ui/src/main/js/pages/Job.js
index 6a9bd7e..070f1e4 100644
--- a/ui/src/main/js/pages/Job.js
+++ b/ui/src/main/js/pages/Job.js
@@ -27,7 +27,8 @@ export default class Job extends React.Component {
       configGroups: props.configGroups,
       tasks: props.tasks,
       updates: props.updates,
-      pendingReasons: props.pendingReasons
+      pendingReasons: props.pendingReasons,
+      cronJob: props.cronJob
     };
   }
 
@@ -58,6 +59,20 @@ export default class Job extends React.Component {
         configGroups: response.result.configSummaryResult.summary.groups
       });
     });
+    api.getJobSummary(role, (response) => {
+      const cronJob = response.result.jobSummaryResult.summaries.find((j) => {
+        return j.job.key.environment === that.props.match.params.environment &&
+          j.job.key.name === that.props.match.params.name &&
+          !isNully(j.job.cronSchedule);
+      });
+
+      if (cronJob) {
+        that.setState({
+          cluster: response.serverInfo.clusterName,
+          cronJob
+        });
+      }
+    });
 
     const updateQuery = new JobUpdateQuery();
     updateQuery.jobKey = key;
@@ -123,7 +138,9 @@ export default class Job extends React.Component {
 
   jobStatusTab() {
     const activeTasks = sort(this.state.tasks.filter(isActive), (t) => t.assignedTask.instanceId);
-    const numberConfigs = isNully(this.state.configGroups) ? '' : this.state.configGroups.length;
+    const numberConfigs = isNully(this.state.cronJob)
+      ? isNully(this.state.configGroups) ? '' : this.state.configGroups.length
+      : 1;
     return {
       id: JOB_STATUS_TAB,
       name: 'Job Status',
@@ -143,7 +160,7 @@ export default class Job extends React.Component {
               icon: 'info-sign',
               id: TASK_CONFIG_TAB,
               name: `Configuration (${numberConfigs})`,
-              content: <JobConfig groups={this.state.configGroups} />
+              content: <JobConfig cronJob={this.state.cronJob} groups={this.state.configGroups} />
             }]} />
       </PanelGroup>)
     };

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/pages/__tests__/Job-test.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/pages/__tests__/Job-test.js b/ui/src/main/js/pages/__tests__/Job-test.js
index 09dd54e..03ef20d 100644
--- a/ui/src/main/js/pages/__tests__/Job-test.js
+++ b/ui/src/main/js/pages/__tests__/Job-test.js
@@ -23,7 +23,8 @@ function apiSpy() {
     getTasksWithoutConfigs: jest.fn(),
     getPendingReason: jest.fn(),
     getConfigSummary: jest.fn(),
-    getJobUpdateDetails: jest.fn()
+    getJobUpdateDetails: jest.fn(),
+    getJobSummary: jest.fn()
   };
 }
 

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/js/utils/Thrift.js
----------------------------------------------------------------------
diff --git a/ui/src/main/js/utils/Thrift.js b/ui/src/main/js/utils/Thrift.js
index 4336bd1..a097037 100644
--- a/ui/src/main/js/utils/Thrift.js
+++ b/ui/src/main/js/utils/Thrift.js
@@ -3,6 +3,7 @@ import { invert } from 'utils/Common';
 export const SCHEDULE_STATUS = invert(ScheduleStatus);
 export const UPDATE_STATUS = invert(JobUpdateStatus);
 export const UPDATE_ACTION = invert(JobUpdateAction);
+export const COLLISION_POLICY = invert(CronCollisionPolicy);
 
 export const OKAY_SCHEDULE_STATUS = [
   ScheduleStatus.RUNNING,

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/src/main/sass/components/_job-page.scss
----------------------------------------------------------------------
diff --git a/ui/src/main/sass/components/_job-page.scss b/ui/src/main/sass/components/_job-page.scss
index cd03832..91b731f 100644
--- a/ui/src/main/sass/components/_job-page.scss
+++ b/ui/src/main/sass/components/_job-page.scss
@@ -68,6 +68,10 @@
       }
     }
 
+    .cron-config-summary {
+      width: 500px !important;
+    }
+
     tr:first-child {
       background-color: $grid_color;
     }

http://git-wip-us.apache.org/repos/asf/aurora/blob/c6388774/ui/test-setup.js
----------------------------------------------------------------------
diff --git a/ui/test-setup.js b/ui/test-setup.js
index a86a89a..5b739de 100644
--- a/ui/test-setup.js
+++ b/ui/test-setup.js
@@ -64,3 +64,9 @@ global.JobUpdateAction = {
   'INSTANCE_UPDATE_FAILED' : 5,
   'INSTANCE_ROLLBACK_FAILED' : 6
 };
+
+global.CronCollisionPolicy = {
+  'KILL_EXISTING': 0,
+  'CANCEL_NEW': 1,
+  'RUN_OVERLAP': 2
+};