Browse Source

AMBARI-15724 Integrate Version Registration in Select Stack Page (zhewang)

Zhe (Joe) Wang 9 years ago
parent
commit
0b77adc2f7
36 changed files with 2677 additions and 930 deletions
  1. 123 36
      ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js
  2. 10 0
      ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
  3. 4 0
      ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
  4. 40 3
      ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
  5. 52 16
      ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
  6. 56 35
      ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
  7. 556 0
      ambari-web/app/assets/data/wizard/stack/HDP_version_definitions.json
  8. 321 23
      ambari-web/app/controllers/installer.js
  9. 36 4
      ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
  10. 7 1
      ambari-web/app/controllers/main/service/add_controller.js
  11. 29 0
      ambari-web/app/controllers/wizard.js
  12. 84 1
      ambari-web/app/controllers/wizard/step1_controller.js
  13. 31 3
      ambari-web/app/controllers/wizard/step8_controller.js
  14. 13 0
      ambari-web/app/mappers/repository_version_mapper.js
  15. 44 9
      ambari-web/app/mappers/stack_mapper.js
  16. 30 2
      ambari-web/app/messages.js
  17. 20 31
      ambari-web/app/models/stack.js
  18. 1 0
      ambari-web/app/models/stack_version/repository_version.js
  19. 8 1
      ambari-web/app/routes/add_service_routes.js
  20. 155 0
      ambari-web/app/styles/application.less
  21. 1 1
      ambari-web/app/templates/main/admin/stack_upgrade/edit_repositories.hbs
  22. 1 1
      ambari-web/app/templates/main/admin/stack_upgrade/services.hbs
  23. 5 5
      ambari-web/app/templates/main/admin/stack_upgrade/versions.hbs
  24. 170 89
      ambari-web/app/templates/wizard/step1.hbs
  25. 1 1
      ambari-web/app/templates/wizard/step4.hbs
  26. 76 0
      ambari-web/app/utils/ajax/ajax.js
  27. 16 0
      ambari-web/app/utils/db.js
  28. 8 3
      ambari-web/app/views/main/admin/stack_upgrade/services_view.js
  29. 1 1
      ambari-web/app/views/main/admin/stack_upgrade/upgrade_version_box_view.js
  30. 226 127
      ambari-web/app/views/wizard/step1_view.js
  31. 3 24
      ambari-web/test/controllers/installer_test.js
  32. 3 2
      ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js
  33. 35 12
      ambari-web/test/controllers/wizard/step8_test.js
  34. 506 168
      ambari-web/test/mappers/stack_mapper_test.js
  35. 1 24
      ambari-web/test/views/main/admin/stack_upgrade/services_view_test.js
  36. 4 307
      ambari-web/test/views/wizard/step1_view_test.js

+ 123 - 36
ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js

@@ -36,14 +36,22 @@ angular.module('ambariAdminConsole')
     display_name: ''
   };
 
-  $scope.option1 = {
+  $scope.publicOption = {
     index: 1,
+    hasError: false
+  };
+  $scope.localOption = {
+    index: 2,
+    hasError: false
+  };
+  $scope.option1 = {
+    index: 3,
     displayName: $t('versions.uploadFile'),
     file: '',
     hasError: false
   };
   $scope.option2 = {
-    index: 2,
+    index: 4,
     displayName: $t('versions.enterURL'),
     url: $t('versions.defaultURL'),
     hasError: false
@@ -51,20 +59,42 @@ angular.module('ambariAdminConsole')
   $scope.selectedOption = {
     index: 1
   };
+  $scope.selectedLocalOption = {
+    index: 3
+  };
 
   /**
    * User can select ONLY one option to upload version definition file
    */
+  $scope.togglePublicLocalOptionSelect = function () {
+    $scope.option1.hasError = false;
+    $scope.option2.hasError = false;
+  };
   $scope.toggleOptionSelect = function () {
     $scope.option1.hasError = false;
     $scope.option2.hasError = false;
   };
+  $scope.togglePublicLocalOptionSelect = function () {
+    if ($scope.selectedOption.index == $scope.publicOption.index && $scope.selectedPublicRepoVersion) {
+      $scope.setVersionSelected($scope.selectedPublicRepoVersion);
+    }
+  };
   $scope.clearOptionsError = function () {
     $scope.option1.hasError = false;
     $scope.option2.hasError = false;
   };
   $scope.readInfoButtonDisabled = function () {
-    return $scope.option1.index == $scope.selectedOption.index ? !$scope.option1.file : !$scope.option2.url;
+    if ($scope.selectedOption.index == $scope.publicOption.index) return true;
+    return $scope.option1.index == $scope.selectedLocalOption.index ? !$scope.option1.file : !$scope.option2.url;
+  };
+  $scope.isAddOsButtonDisabled = function () {
+    var selectedCnt = 0;
+    angular.forEach($scope.osList, function (os) {
+      if (os.selected) {
+        selectedCnt ++;
+      }
+    });
+    return $scope.osList.length == selectedCnt;
   };
 
   $scope.allInfoCategoriesBlank = function () {
@@ -92,14 +122,14 @@ angular.module('ambariAdminConsole')
   $scope.readVersionInfo = function(){
     var data = {};
     var isXMLdata = false;
-    if ($scope.option2.index == $scope.selectedOption.index) {
+    if ($scope.option2.index == $scope.selectedLocalOption.index) {
       var url = $scope.option2.url;
       data = {
         "VersionDefinition": {
           "version_url": url
         }
       };
-    } else if ($scope.option1.index == $scope.selectedOption.index) {
+    } else if ($scope.option1.index == $scope.selectedLocalOption.index) {
       isXMLdata = true;
       // load from file browser
       data = $scope.option1.file;
@@ -109,34 +139,7 @@ angular.module('ambariAdminConsole')
       if (versionInfo.id && versionInfo.stackName && versionInfo.stackVersion) {
         Stack.getRepo(versionInfo.id, versionInfo.stackName, versionInfo.stackVersion)
           .then(function (response) {
-            $scope.id = response.id;
-            $scope.isPatch = response.type == 'PATCH';
-            $scope.stackNameVersion = response.stackNameVersion || $t('common.NA');
-            $scope.displayName = response.displayName || $t('common.NA');
-            $scope.version = response.version || $t('common.NA');
-            $scope.actualVersion = response.actualVersion || $t('common.NA');
-            $scope.updateObj = response.updateObj;
-            $scope.upgradeStack = {
-              stack_name: response.stackName,
-              stack_version: response.stackVersion,
-              display_name: response.displayName
-            };
-            $scope.services = response.services || [];
-            //save default values of repos to check if they were changed
-            $scope.defaulfOSRepos = {};
-            response.updateObj.operating_systems.forEach(function(os) {
-              $scope.defaulfOSRepos[os.OperatingSystems.os_type] = {
-                defaultBaseUrl: os.repositories[0].Repositories.base_url,
-                defaultUtilsUrl: os.repositories[1].Repositories.base_url
-              };
-            });
-            $scope.repoVersionFullName = response.repoVersionFullName;
-            angular.forEach(response.osList, function (os) {
-              os.selected = true;
-            });
-            $scope.osList = response.osList;
-            // load supported os type base on stack version
-            $scope.afterStackVersionRead();
+            $scope.setVersionSelected(response);
         });
       }
     })
@@ -233,7 +236,41 @@ angular.module('ambariAdminConsole')
         updateRepoUrl = true;
       }
     });
-    $scope.updateRepoVersions();
+    if ($scope.isPublicVersion) {
+      return Stack.validateBaseUrls($scope.skipValidation, $scope.osList, $scope.upgradeStack).then(function (invalidUrls) {
+        if (invalidUrls.length === 0) {
+          var data = {
+            "VersionDefinition": {
+              "available": $scope.id
+            }
+          };
+          var repoUpdate = {
+            operating_systems: $scope.updateObj.operating_systems
+          };
+          Stack.postVersionDefinitionFile(false, data).then(function (versionInfo) {
+            if (versionInfo.id && versionInfo.stackName && versionInfo.stackVersion) {
+              Stack.updateRepo(versionInfo.stackName, versionInfo.stackVersion, versionInfo.id, repoUpdate).then(function () {
+                Alert.success($t('versions.alerts.versionEdited', {
+                  stackName: $scope.upgradeStack.stack_name,
+                  versionName: $scope.actualVersion,
+                  displayName: $scope.displayName
+                }));
+                $location.path('/stackVersions');
+              }).catch(function (data) {
+                Alert.error($t('versions.alerts.versionUpdateError'), data.message);
+              });
+            }
+          })
+          .catch(function (data) {
+            Alert.error($t('versions.alerts.readVersionInfoError'), data.message);
+          });
+        } else {
+          Stack.highlightInvalidUrls(invalidUrls);
+        }
+      });
+    } else {
+      $scope.updateRepoVersions();
+    }
   };
 
   $scope.updateRepoVersions = function () {
@@ -247,8 +284,8 @@ angular.module('ambariAdminConsole')
           }));
           $location.path('/stackVersions');
         }).catch(function (data) {
-            Alert.error($t('versions.alerts.versionUpdateError'), data.message);
-          });
+          Alert.error($t('versions.alerts.versionUpdateError'), data.message);
+        });
       } else {
         Stack.highlightInvalidUrls(invalidUrls);
       }
@@ -291,4 +328,54 @@ angular.module('ambariAdminConsole')
     }
     return hasErrors;
   };
+
+
+  $scope.setVersionSelected = function (version) {
+    var response = version;
+    $scope.id = response.id;
+    $scope.isPatch = response.type == 'PATCH';
+    $scope.stackNameVersion = response.stackNameVersion || $t('common.NA');
+    $scope.displayName = response.displayName || $t('common.NA');
+    $scope.actualVersion = response.repositoryVersion || response.actualVersion || $t('common.NA');
+    $scope.isPublicVersion = response.showAvailable == true;
+    $scope.updateObj = response.updateObj;
+    $scope.upgradeStack = {
+      stack_name: response.stackName,
+      stack_version: response.stackVersion,
+      display_name: response.displayName || $t('common.NA')
+    };
+    $scope.services = response.services || [];
+    //save default values of repos to check if they were changed
+    $scope.defaulfOSRepos = {};
+    response.updateObj.operating_systems.forEach(function(os) {
+      $scope.defaulfOSRepos[os.OperatingSystems.os_type] = {
+        defaultBaseUrl: os.repositories[0].Repositories.base_url,
+        defaultUtilsUrl: os.repositories[1].Repositories.base_url
+      };
+    });
+    $scope.repoVersionFullName = response.repoVersionFullName;
+    angular.forEach(response.osList, function (os) {
+      os.selected = true;
+    });
+    $scope.osList = response.osList;
+    // load supported os type base on stack version
+    $scope.afterStackVersionRead();
+  };
+
+  $scope.selectRepoInList = function() {
+    $scope.selectedPublicRepoVersion = this.version;
+    $scope.setVersionSelected(this.version);
+  };
+
+  $scope.fetchPublicVersions = function () {
+    return Stack.allPublicStackVersions().then(function (versions) {
+      if (versions && versions.length) {
+        $scope.selectedPublicRepoVersion = versions[0];
+        $scope.setVersionSelected(versions[0]);
+        $scope.availableStackRepoList = versions.length == 1 ? [] : versions;
+      }
+    });
+  };
+
+  $scope.fetchPublicVersions();
 }]);

+ 10 - 0
ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js

@@ -236,6 +236,16 @@ angular.module('ambariAdminConsole')
     }
   };
 
+  $scope.isAddOsButtonDisabled = function () {
+    var selectedCnt = 0;
+    angular.forEach($scope.osList, function (os) {
+      if (os.selected) {
+        selectedCnt ++;
+      }
+    });
+    return $scope.osList.length == selectedCnt;
+  };
+
   $scope.hasNotDeletedRepo = function () {
     //check if any repository has been selected for deleting
     //if yes, drop down should be displayed

+ 4 - 0
ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js

@@ -335,6 +335,10 @@ angular.module('ambariAdminConsole')
       'current': 'Current',
       'inUse': 'In Use',
       'installed': 'Installed',
+      'usePublic': "Use Public Repository",
+      'selectVersion': "Select Version",
+      'selectVersionEmpty': "No other repositories",
+      'useLocal': "Use Local Repository",
       'uploadFile': 'Upload Version Definition File',
       'enterURL': 'Version Definition File URL',
       'defaultURL': 'https://',

+ 40 - 3
ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js

@@ -80,6 +80,44 @@ angular.module('ambariAdminConsole')
       return deferred.promise;
     },
 
+    allPublicStackVersions: function() {
+      var url = '/version_definitions?fields=operating_systems/repositories/Repositories/*,VersionDefinition/stack_services,VersionDefinition/repository_version' +
+        '&VersionDefinition/show_available=true&VersionDefinition/stack_name=HDP';
+      var deferred = $q.defer();
+      $http.get(Settings.baseUrl + url, {mock: 'version/versions.json'})
+        .success(function (data) {
+          var versions = [];
+          angular.forEach(data.items, function(version) {
+            var versionObj = {
+              id: version.VersionDefinition.id,
+              stackName: version.VersionDefinition.stack_name,
+              stackVersion: version.VersionDefinition.stack_version,
+              stackNameVersion:  version.VersionDefinition.stack_name + '-' + version.VersionDefinition.stack_version,
+              displayName: version.VersionDefinition.stack_name + '-' + version.VersionDefinition.repository_version.split('-')[0], //HDP-2.3.4.0
+              displayNameFull: version.VersionDefinition.stack_name + '-' + version.VersionDefinition.repository_version, //HDP-2.3.4.0-23
+              repositoryVersion: version.VersionDefinition.repository_version,
+              showAvailable: version.VersionDefinition.show_available,
+              osList: version.operating_systems,
+              updateObj: version
+            };
+            var services = [];
+            angular.forEach(version.VersionDefinition.stack_services, function (service) {
+              services.push({
+                name: service.name,
+                version: service.versions[0]
+              });
+            });
+            versionObj.services = services;
+            versions.push(versionObj);
+          });
+          deferred.resolve(versions)
+        })
+        .error(function (data) {
+          deferred.reject(data);
+        });
+      return deferred.promise;
+    },
+
     allRepos: function (filter, pagination) {
       var versionFilter = filter.version;
       var url = '/stacks?fields=versions/repository_versions/RepositoryVersions';
@@ -183,11 +221,10 @@ angular.module('ambariAdminConsole')
           updateObj: data.repository_versions[0]
         };
         var services = [];
-        angular.forEach(data.repository_versions[0].RepositoryVersions.services, function (service) {
+        angular.forEach(data.repository_versions[0].RepositoryVersions.stack_services, function (service) {
           services.push({
             name: service.name,
-            version: service.versions[0].version,
-            components: service.versions[0].components
+            version: service.versions[0]
           });
         });
         response.services = services;

+ 52 - 16
ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css

@@ -1451,43 +1451,73 @@ thead.view-permission-header > tr > th {
   color: white;
 }
 #upload-definition-file-panel {
-  background-color: #f9f9f9;
-  padding: 20px 10px 5px 10px;
+  padding: 5px 10px 5px 10px;
   margin-bottom: 15px;
 }
-#upload-definition-file-panel .introduction-info {
-  padding: 10px 10px 15px 15px;
-  font-size: 15px;
-  line-height: 1.7;
+
+#upload-definition-file-panel .option-radio {
+  padding: 15px 5px;
+  font-weight: bold;;
+}
+#upload-definition-file-panel .stack-version-selection {
+   padding-left: 25px;
+ }
+#upload-definition-file-panel .stack-version-selection .select-version-label {
+  padding-top: 4px;
+}
+#upload-definition-file-panel .stack-version-selection .select-version-label.disabled {
+  color: #999999;
+}
+#upload-definition-file-panel .dropdown-menu li a {
+  cursor: pointer;
+}
+.register-version-options {
+  padding-left: 25px;
 }
 .register-version-options .read-info-button {
   margin-top: 10px;
 }
-
 .register-version-options .option-radio-button {
   padding-top: 5px;
 }
-
+.register-version-options .option-radio-button label {
+  font-weight: normal;
+}
 .register-version-options .choose-file-input {
   padding-top: 6px;
   padding-bottom: 20px;
 }
-
 .register-version-form .details-panel .patch-icon {
   color: #ff4500;
 }
 .register-version-form .deregister-button {
-    margin-top: -23px;
+  margin-top: -23px;
 }
 .register-version-form .version-info {
-    padding-top: 7px;
-    margin-top: 0;
-    margin-bottom: 0;
+  padding-top: 7px;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+.register-version-form .details-panel .version-info-section {
+  margin-top: 10px;
+}
+.register-version-form .details-panel .version-contents-section {
+  max-height: 200px;
+  overflow: auto;
+  border: 1px solid #ddd;
+  padding: 8px 25px;
+  margin: 8px;
+}
+
+.register-version-form .details-panel .control-label {
+  text-align: left;
+  padding: 7px 2px;
+  font-weight: normal;
 }
 
-.register-version-form .contents-panel .version-contents-body {
-    max-height: 150px;
-    overflow: auto;
+.register-version-form .details-panel .version-info {
+  font-weight: bold;
+  padding: 7px 2px;
 }
 
 .register-version-form .repos-panel .remove-icon {
@@ -1504,6 +1534,12 @@ thead.view-permission-header > tr > th {
 .register-version-form .repos-panel .os-type-label {
   margin-top: 27px;;
 }
+.register-version-form .dropdown-menu li a {
+  cursor: pointer;
+}
+.register-version-form .repos-panel .checkbox {
+  margin: 0px 5px;
+}
 
 #stack-versions .no-version-alert {
   text-align: center;

+ 56 - 35
ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html

@@ -32,27 +32,56 @@
 </div>
 <hr>
 
+
+
 <div id="upload-definition-file-panel" ng-if="createController">
-  <div class="introduction-info hide-soft" ng-class="{'visible': allInfoCategoriesBlank()}" role="alert">{{'versions.introduction' | translate}}</div>
+
+  <div class="col-sm-12 option-radio clearfix">
+    <input type="radio" ng-model="selectedOption.index" value="1" ng-change="togglePublicLocalOptionSelect()">   {{'versions.usePublic' | translate}}
+  </div>
+
+  <div class="clearfix stack-version-selection">
+    <div class="col-sm-3 select-version-label" ng-class="{'disabled': selectedOption.index==2}">
+      {{'versions.selectVersion' | translate}}
+    </div>
+    <div class="col-sm-7 right-stack-info">
+      <div class="repo-list-button btn-group" dropdown>
+        <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown" ng-disabled="(selectedOption.index==2)">{{selectedPublicRepoVersion.displayNameFull}} &nbsp;<span class="caret"></span></button>
+        <ul class="dropdown-menu available-repos-dropdown"  ng-if="availableStackRepoList">
+          <li ng-repeat="version in availableStackRepoList" class="" ng-if="version.displayNameFull !== selectedPublicRepoVersion.displayNameFull">
+            <a ng-click="selectRepoInList()">{{version.displayNameFull}}</a></li>
+        </ul>
+        <ul class="dropdown-menu available-repos-dropdown"  ng-if="!availableStackRepoList || availableStackRepoList.length == 0">
+          <li class="disabled"><a>{{'versions.selectVersionEmpty' | translate}}</a></li>
+        </ul>
+      </div>
+    </div>
+  </div>
+
+  <div class="col-sm-12 option-radio clearfix">
+    <input type="radio" ng-model="selectedOption.index" value="2" ng-change="togglePublicLocalOptionSelect()">   {{'versions.useLocal' | translate}}
+  </div>
+
   <div class="clearfix register-version-options">
     <div class="col-sm-5 option-radio-button">
       <label class="option-label">
-        <input type="radio" ng-model="selectedOption.index" value="1" ng-change="toggleOptionSelect()"> {{'versions.uploadFile' | translate}}
+        <input type="radio" ng-model="selectedLocalOption.index" value="3" ng-change="toggleOptionSelect()" ng-disabled="(selectedOption.index==1)"> {{'versions.uploadFile' | translate}}
       </label>
     </div>
     <div class="col-sm-7">
-      <input type="file" class="choose-file-input" ng-model="option1.file" onchange="angular.element(this).scope().onFileSelect(this)"/>
+      <input type="file" class="choose-file-input" ng-model="option1.file" ng-disabled="(selectedOption.index==1) || !(selectedLocalOption.index==3)"
+             onchange="angular.element(this).scope().onFileSelect(this)"/>
     </div>
   </div>
   <div class="clearfix register-version-options bottom-margin">
     <div class="col-sm-5 option-radio-button">
       <label class="option-label">
-        <input type="radio" ng-model="selectedOption.index" value="2" ng-change="toggleOptionSelect()"> {{'versions.enterURL' | translate}}
+        <input type="radio" ng-model="selectedLocalOption.index" value="4" ng-change="toggleOptionSelect()" ng-disabled="(selectedOption.index==1)"> {{'versions.enterURL' | translate}}
       </label>
     </div>
     <div class="col-sm-7">
       <div class="form-group {{option2.name}}" ng-class="{'has-error': option2.url.hasError }">
-        <div class=""><input type="text" class="form-control" ng-model="option2.url" ng-change="clearOptionsError()" ng-disabled="!(selectedOption.index==2)"></div>
+        <div class=""><input type="text" class="form-control" ng-model="option2.url" ng-change="clearOptionsError()" ng-disabled="(selectedOption.index==1) || !(selectedLocalOption.index==4)"></div>
       </div>
     </div>
     <div class="col-sm-12 read-info-button">
@@ -95,34 +124,26 @@
         </div>
     </div>
     <div class="panel-body">
-      <div class="clearfix">
-        <label class="control-label col-sm-3">{{'versions.details.stackName' | translate}}</label>
-        <div class="version-info col-sm-7">{{stackNameVersion}}</div>
-        <div class="col-sm-2 patch-icon" ng-if="isPatch"><span class="glyphicon glyphicon-tree-deciduous"></span>{{'versions.patch' | translate}}</div>
-      </div>
-      <div class="clearfix">
-        <label class="control-label col-sm-3">{{'versions.details.displayName' | translate}}</label>
-        <div class="version-info col-sm-9">{{displayName}}</div>
-      </div>
-      <div class="clearfix">
-        <label class="control-label col-sm-3">{{'versions.details.version' | translate}}</label>
-        <div class="version-info col-sm-9">{{version}}</div>
-      </div>
-      <div class="clearfix">
-        <label class="control-label col-sm-3">{{'versions.details.actualVersion' | translate}}</label>
-        <div class="version-info col-sm-9">{{actualVersion}}</div>
+      <div class="col-sm-5 version-info-section">
+        <div class="clearfix">
+          <label class="control-label col-sm-7">{{'versions.details.stackName' | translate}}</label>
+          <div class="version-info col-sm-3">{{stackNameVersion}}</div>
+          <div class="col-sm-2 patch-icon" ng-if="isPatch"><span class="glyphicon glyphicon-tree-deciduous"></span>{{'versions.patch' | translate}}</div>
+        </div>
+        <div class="clearfix">
+          <label class="control-label col-sm-7">{{'versions.details.displayName' | translate}}</label>
+          <div class="version-info col-sm-5">{{displayName}}</div>
+        </div>
+        <div class="clearfix">
+          <label class="control-label col-sm-7">{{'versions.details.version' | translate}}</label>
+          <div class="version-info col-sm-5">{{actualVersion}}</div>
+        </div>
       </div>
-    </div>
-  </div>
-  <div class="panel panel-default contents-panel">
-    <div class="panel-heading">
-      <h3 class="panel-title">{{'versions.contents.title' | translate}}</h3>
-    </div>
-    <div class="panel-body version-contents-body">
-      <div class="alert alert-info hide-soft" ng-class="{'visible' : !services || !services.length}" role="alert">{{'versions.contents.empty' | translate}}</div>
-      <div class="clearfix" ng-repeat="service in services">
-        <label class="control-label col-sm-3">{{service.name}}</label>
-        <div class="version-info col-sm-9">{{service.version}}</div>
+      <div class="col-sm-6 version-contents-section">
+        <div class="alert alert-info hide-soft" ng-class="{'visible' : !services || !services.length}" role="alert">{{'versions.contents.empty' | translate}}</div>
+        <div class="clearfix" ng-repeat="service in services">
+          <div class="version-info col-sm-9">{{service.name}} ({{service.version}})</div>
+        </div>
       </div>
     </div>
   </div>
@@ -164,14 +185,14 @@
         </div>
       </div>
         <div class="btn-group pull-right" dropdown>
-          <button class="btn dropdown-toggle">
+          <button class="btn dropdown-toggle" ng-disabled="isAddOsButtonDisabled()">
             <span class="glyphicon glyphicon-plus"></span> {{'common.add' | translate: '{term: constants.os}'}} &nbsp;<span class="caret"></span></button>
           <ul class="dropdown-menu" ng-class="{'hidden': hasNotDeletedRepo()}">
             <li ng-repeat="os in osList"><a ng-if="os.selected==false" ng-click="addOS()">{{os.OperatingSystems.os_type}}</a></li>
           </ul>
         </div>
       <div class="clearfix">
-        <div class="col-sm-12" id="skip-validation">
+        <div class="col-sm-9" id="skip-validation">
           <div class="checkbox">
             <label>
               <input type="checkbox" ng-model="skipValidation" ng-change="clearErrors()">
@@ -179,7 +200,7 @@
             </label>
           </div>
         </div>
-        <div class="col-sm-12" id="use-redhat">
+        <div class="col-sm-9" id="use-redhat">
           <div class="checkbox">
             <label>
               <input type="checkbox" ng-model="useRedhatSatellite" ng-change="clearErrors()">

+ 556 - 0
ambari-web/app/assets/data/wizard/stack/HDP_version_definitions.json

@@ -0,0 +1,556 @@
+{
+  "href" : "http://c6401.ambari.apache.org:8080/api/v1/version_definitions?fields=operating_systems/repositories/Repositories/*,VersionDefinition/stack_services&show_available=true&VersionDefinition/stack_name=HDP",
+  "items" : [
+    {
+      "VersionDefinition" : {
+        "id" : 1,
+        "show_available": true,
+        "stack_name" : "HDP",
+        "stack_version" : "2.3",
+        "repository_version" : "2.3.4.0-3396",
+        "type" : "STANDARD",
+        "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3396.xml",
+        "release" : {
+          "build" : "3396",
+          "compatible_with" : "2.3.[0-3].0",
+          "notes" : "http://example.com",
+          "version" : "2.3.4.0"
+        },
+        "stack_services" : [
+          {
+            "name" : "HDFS",
+            "display_name" : "HDFS",
+            "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+            "versions" : [
+              "2.7.1.2.3396"
+            ]
+          },
+          {
+            "name" : "YARN",
+            "display_name" : "YARN",
+            "comment" : "",
+            "versions" : [
+              "1.7.3.3396"
+            ]
+          },
+          {
+            "name" : "ZOOKEEPER",
+            "display_name" : "ZooKeeper",
+            "comment" : "",
+            "versions" : [
+              "1.7.3.3396"
+            ]
+          }
+        ]
+      },
+      "operating_systems" : [
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+          "OperatingSystems" : {
+            "os_type" : "debian7",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        },
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
+          "OperatingSystems" : {
+            "os_type" : "redhat6",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        }
+      ]
+    },
+
+    {
+      "VersionDefinition" : {
+        "id" : 2,
+        "stack_name" : "HDP",
+        "stack_version" : "2.3",
+        "show_available": true,
+        "repository_version" : "2.3.4.0-3397",
+        "type" : "STANDARD",
+        "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3397.xml",
+        "release" : {
+          "build" : "3397",
+          "compatible_with" : "2.3.[0-3].0",
+          "notes" : "http://example.com",
+          "version" : "2.3.4.0"
+        },
+        "stack_services" : [
+          {
+            "name" : "HDFS",
+            "display_name" : "HDFS",
+            "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+            "versions" : [
+              "2.7.1.2-3397"
+            ]
+          },
+          {
+            "name" : "YARN",
+            "display_name" : "YARN",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3397"
+            ]
+          },
+          {
+            "name" : "HBase",
+            "display_name" : "HBase",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3397"
+            ]
+          },
+          {
+            "name" : "ZOOKEEPER",
+            "display_name" : "ZooKeeper",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3397"
+            ]
+          },
+          {
+            "name" : "Hive",
+            "display_name" : "Hive",
+            "comment" : "",
+            "versions" : [
+              "1.1.0-3397"
+            ]
+          }
+        ]
+      },
+      "operating_systems" : [
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+          "OperatingSystems" : {
+            "os_type" : "debian7",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        },
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
+          "OperatingSystems" : {
+            "os_type" : "redhat6",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        }
+      ]
+    },
+
+    {
+      "VersionDefinition" : {
+        "id" : 5,
+        "stack_name" : "HDP",
+        "stack_version" : "2.3",
+        "show_available": true,
+        "repository_version" : "2.3.6.0-3646",
+        "type" : "STANDARD",
+        "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3646.xml",
+        "release" : {
+          "build" : "3646",
+          "compatible_with" : "2.3.[0-6].0",
+          "notes" : "http://example.com",
+          "version" : "2.3.6.0"
+        },
+        "stack_services" : [
+          {
+            "name" : "HDFS",
+            "display_name" : "HDFS",
+            "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+            "versions" : [
+              "2.7.1.2-3646"
+            ]
+          },
+          {
+            "name" : "YARN",
+            "display_name" : "YARN",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3646"
+            ]
+          },
+          {
+            "name" : "HBase",
+            "display_name" : "HBase",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3646"
+            ]
+          },
+          {
+            "name" : "ZOOKEEPER",
+            "display_name" : "ZooKeeper",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-3646"
+            ]
+          },
+          {
+            "name" : "Hive",
+            "display_name" : "Hive",
+            "comment" : "",
+            "versions" : [
+              "1.1.0-3646"
+            ]
+          }
+        ]
+      },
+      "operating_systems" : [
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+          "OperatingSystems" : {
+            "os_type" : "debian7",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        },
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
+          "OperatingSystems" : {
+            "os_type" : "redhat6",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.3"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-2.3",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                "mirrors_list" : "",
+                "os_type" : "redhat6",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.3"
+              }
+            }
+          ]
+        }
+      ]
+    },
+
+
+    {
+      "VersionDefinition" : {
+        "id" : 3,
+        "stack_name" : "HDP",
+        "stack_version" : "2.4",
+        "show_available": true,
+        "repository_version" : "2.4.0.0-169",
+        "type" : "STANDARD",
+        "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_169.xml",
+        "release" : {
+          "build" : "169",
+          "compatible_with" : "2.4.[0-3].0",
+          "notes" : "http://example.com",
+          "version" : "2.4.0.0"
+        },
+        "stack_services" : [
+          {
+            "name" : "HDFS",
+            "display_name" : "HDFS",
+            "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+            "versions" : [
+              "2.7.1.2-169"
+            ]
+          },
+          {
+            "name" : "YARN",
+            "display_name" : "YARN",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-169"
+            ]
+          },
+          {
+            "name" : "HBase",
+            "display_name" : "HBase",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-169"
+            ]
+          },
+          {
+            "name" : "ZOOKEEPER",
+            "display_name" : "ZooKeeper",
+            "comment" : "",
+            "versions" : [
+              "1.7.3-169"
+            ]
+          },
+          {
+            "name" : "Hive",
+            "display_name" : "Hive",
+            "comment" : "",
+            "versions" : [
+              "1.1.0-169"
+            ]
+          },
+          {
+            "name" : "MAPREDUCE2",
+            "display_name" : "MapReduce2",
+            "comment" : "service",
+            "versions" : [
+              "2.7.1.2-169"
+            ]
+          },
+          {
+            "name" : "Slider",
+            "display_name" : "Slider",
+            "comment" : "service",
+            "versions" : [
+              "2.7.1.2-169"
+            ]
+          },
+          {
+            "name" : "Pig",
+            "display_name" : "Pig",
+            "comment" : "service",
+            "versions" : [
+              "2.7.1.2-169"
+            ]
+          },
+          {
+            "name" : "Sqoop",
+            "display_name" : "Sqoop",
+            "comment" : "service",
+            "versions" : [
+              "2.7.1.2-169"
+            ]
+          }
+        ]
+      },
+      "operating_systems" : [
+        {
+          "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+          "OperatingSystems" : {
+            "os_type" : "debian7",
+            "repository_version_id" : 1,
+            "stack_name" : "HDP",
+            "stack_version" : "2.4"
+          },
+          "repositories" : [
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-2.4",
+                "repo_name" : "HDP",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.4"
+              }
+            },
+            {
+              "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+              "Repositories" : {
+                "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                "mirrors_list" : "",
+                "os_type" : "debian7",
+                "repo_id" : "HDP-UTILS-1.1.0.20",
+                "repo_name" : "HDP-UTILS",
+                "repository_version_id" : 1,
+                "stack_name" : "HDP",
+                "stack_version" : "2.4"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 321 - 23
ambari-web/app/controllers/installer.js

@@ -19,6 +19,7 @@
 
 var App = require('app');
 var stringUtils = require('utils/string_utils');
+var validator = require('utils/validator');
 
 App.InstallerController = App.WizardController.extend({
 
@@ -139,7 +140,10 @@ App.InstallerController = App.WizardController.extend({
     var stackServices = App.StackService.find().mapProperty('serviceName');
     if (!(stackServices && !!stackServices.length && App.StackService.find().objectAt(0).get('stackVersion') == App.get('currentStackVersionNumber'))) {
       this.loadServiceComponents().complete(function () {
-        self.set('content.services', App.StackService.find());
+        self.set('content.services', App.StackService.find().forEach(function (item) {
+          // user the service version from VersionDefinition
+          item.set('serviceVersionDisplay', App.Stack.find().findProperty('isSelected', true).get('stackServices').findProperty('name', item.get('serviceName')).get('latestVersion'));
+        }));
         dfd.resolve();
       });
     } else {
@@ -241,7 +245,7 @@ App.InstallerController = App.WizardController.extend({
     App.Tab.find().clear();
     this.set('stackConfigsLoaded', false);
     if (stacks && stacks.get('length')) {
-      App.set('currentStackVersion', App.Stack.find().findProperty('isSelected').get('id'));
+      App.set('currentStackVersion', App.Stack.find().findProperty('isSelected').get('stackNameVersion'));
       dfd.resolve(true);
     } else {
       App.ajax.send({
@@ -278,12 +282,12 @@ App.InstallerController = App.WizardController.extend({
     var requests = [];
     this.get('stackNames').forEach(function (stackName) {
       requests.push(App.ajax.send({
-        name: 'wizard.stacks_versions',
+        name: 'wizard.stacks_versions_definitions',
         sender: this,
         data: {
           stackName: stackName
         },
-        success: 'loadStacksVersionsSuccessCallback',
+        success: 'loadStacksVersionsDefinitionsSuccessCallback',
         error: 'loadStacksVersionsErrorCallback'
       }));
     }, this);
@@ -299,30 +303,111 @@ App.InstallerController = App.WizardController.extend({
   /**
    * Parse loaded data and create array of stacks objects
    */
-  loadStacksVersionsSuccessCallback: function (data) {
+  loadStacksVersionsDefinitionsSuccessCallback: function (data) {
+    var self = this;
     var stacks = App.db.getStacks();
+    var repos = App.db.getRepos();
     var isStacksExistInDb = stacks && stacks.length;
     if (isStacksExistInDb) {
       stacks.forEach(function (_stack) {
-        var stack = data.items.filterProperty('Versions.stack_name', _stack.stack_name).findProperty('Versions.stack_version', _stack.stack_version);
+        var stack = data.items.findProperty('VersionDefinition.repository_version', _stack.repository_version);
         if (stack) {
-          stack.Versions.is_selected = _stack.is_selected;
+          stack.VersionDefinition.is_selected = _stack.is_selected;
         }
       }, this);
     }
-    App.stackMapper.map(data);
-    if (!this.decrementProperty('loadStacksRequestsCounter')) {
-      if (!isStacksExistInDb) {
-        var defaultStackVersion = App.Stack.find().findProperty('id', App.defaultStackVersion);
-        if (defaultStackVersion) {
-          defaultStackVersion.set('isSelected', true)
+
+    var versionDefinition = data.items[0];
+    // to display repos panel, should map all available operating systems including empty ones
+    this.getSupportedOSList(versionDefinition.VersionDefinition.stack_name, versionDefinition.VersionDefinition.stack_version).complete(function () {
+      var existedOS = versionDefinition.operating_systems;
+      var existedMap = {};
+      existedOS.map(function (existedOS) {
+        existedOS.isSelected = true;
+        existedMap[existedOS.OperatingSystems.os_type] = existedOS;
+      });
+      self.get('allSupportedOS').forEach(function(supportedOS) {
+        if(!existedMap[supportedOS.OperatingSystems.os_type]) {
+          supportedOS.isSelected = false;
+          supportedOS.repositories.forEach(function(repo) {
+            repo.Repositories.base_url = '';
+          });
+          existedOS.push(supportedOS);
+        }
+      });
+      App.stackMapper.map(data.items, "VersionDefinition");
+      if (!self.decrementProperty('loadStacksRequestsCounter')) {
+
+        var versionData = self.getSelectedRepoVersionData();
+        if (versionData) {
+          self.postVersionDefinitionFile(versionData.isXMLdata, versionData.data).done(function (versionInfo) {
+            self.mergeChanges(repos);
+            App.Stack.find().setEach('isSelected', false);
+            App.Stack.find().findProperty('id', versionInfo.stackNameVersion + "-" + versionInfo.actualVersion).set('isSelected', true);
+            self.setSelected(isStacksExistInDb);
+          });
         } else {
-          App.Stack.find().objectAt(0).set('isSelected', true);
+          self.setSelected(isStacksExistInDb);
         }
       }
-      this.set('content.stacks', App.Stack.find());
-      App.set('currentStackVersion', App.Stack.find().findProperty('isSelected').get('id'));
+    });
+  },
+
+  mergeChanges: function (repos) {
+    repos.forEach(function (repo) {
+      App.Repository.find().findProperty('id', repo.id).set('baseUrl', repo.base_url);
+    });
+  },
+
+  setSelected: function (isStacksExistInDb) {
+    if (!isStacksExistInDb) {
+      var defaultStackVersion = App.Stack.find().findProperty('stackNameVersion', App.defaultStackVersion);
+      if (defaultStackVersion) {
+        defaultStackVersion.set('isSelected', true)
+      } else {
+        App.Stack.find().objectAt(0).set('isSelected', true);
+      }
     }
+    this.set('content.stacks', App.Stack.find());
+    App.set('currentStackVersion', App.Stack.find().findProperty('isSelected').get('stackNameVersion'));
+  },
+
+  /**
+   * Get the the repo version (to install) info, this data will be POST
+   * @method startDeploy
+   */
+  getSelectedRepoVersionData: function () {
+    var vdfData = App.db.getLocalRepoVDFData();
+    var selectedStack = App.Stack.find().findProperty('isSelected', true);
+    var isXMLdata = false;
+    var data = {};
+    if (selectedStack && selectedStack.get('showAvailable')) {
+      //meaning user selected a public repo
+      data = {
+        "VersionDefinition": {
+          "available": selectedStack.get('id')
+        }
+      };
+      isXMLdata = false;
+    } else if (vdfData && validator.isValidURL(vdfData)) {
+      // meaning user uploaded a VDF via entering URL
+      data = {
+        "VersionDefinition": {
+          "version_url": vdfData
+        }
+      };
+      isXMLdata = false;
+    } else if (vdfData) {
+      // meaning user uploaded a local VDF.xml file
+      isXMLdata = true;
+      data = vdfData;
+    } else {
+      return null;
+    }
+    return {
+      isXMLdata: isXMLdata,
+      data: data
+    };
   },
 
   /**
@@ -372,10 +457,13 @@ App.InstallerController = App.WizardController.extend({
    * set stacks from server to content and local DB
    */
   setStacks: function () {
-    var result = App.Stack.find() || [];
-    Em.assert('Stack model is not populated', result.get('length'));
-    App.db.setStacks(result.slice());
-    this.set('content.stacks', result);
+    var stacks = App.Stack.find() || [];
+    Em.assert('Stack model is not populated', stacks.get('length'));
+    App.db.setStacks(stacks.slice());
+    this.set('content.stacks', stacks);
+
+    var repos = App.Repository.find() || [];
+    App.db.setRepos(repos.slice());
   },
 
   /**
@@ -405,7 +493,6 @@ App.InstallerController = App.WizardController.extend({
    * @param stepController App.WizardStep5Controller
    */
   saveMasterComponentHosts: function (stepController) {
-
     var obj = stepController.get('selectedServicesMasters'),
       hosts = this.getDBProperty('hosts');
 
@@ -506,13 +593,222 @@ App.InstallerController = App.WizardController.extend({
     this.set('content.clients', clients);
   },
 
+  /*
+   * Post version definition file (.xml) to server, DRY_RUN = TRUE
+   */
+  postVersionDefinitionFile: function (isXMLdata, data) {
+    var dfd = $.Deferred();
+    var name = isXMLdata? 'wizard.step1.post_version_definition_file.xml' : 'wizard.step1.post_version_definition_file.url';
+
+    App.ajax.send({
+      name: name,
+      sender: this,
+      data: {
+        dfd: dfd,
+        data: data
+      },
+      success: 'postVersionDefinitionFileSuccessCallback',
+      error: 'postVersionDefinitionFileErrorCallback'
+    });
+    return dfd.promise();
+  },
+
+  /**
+   * onSuccess callback for postVersionDefinitionFile.
+   */
+  postVersionDefinitionFileSuccessCallback: function (_data, request, dataInfo) {
+    if (_data.resources.length && _data.resources[0].VersionDefinition) {
+      var data = _data.resources[0];
+      var self = this;
+      // load the data info to display for details and contents panel
+      var response = {
+        id : data.VersionDefinition.id,
+        stackVersion : data.VersionDefinition.stack_version,
+        stackName: data.VersionDefinition.stack_name,
+        type: data.VersionDefinition.type,
+        stackNameVersion: data.VersionDefinition.stack_name + '-' + data.VersionDefinition.stack_version, /// HDP-2.3
+        actualVersion: data.VersionDefinition.repository_version, /// 2.3.4.0-3846
+        version: data.VersionDefinition.release ? data.VersionDefinition.release.version: null, /// 2.3.4.0
+        releaseNotes: data.VersionDefinition.release ? data.VersionDefinition.release.notes: null,
+        displayName: data.VersionDefinition.release ? data.VersionDefinition.stack_name + '-' + data.VersionDefinition.release.version :
+        data.VersionDefinition.stack_name + '-' + data.VersionDefinition.repository_version, //HDP-2.3.4.0
+        repoVersionFullName : data.VersionDefinition.stack_name + '-' + data.VersionDefinition.repository_version,
+        osList: data.operating_systems,
+        updateObj: data
+      };
+      var services = [];
+      data.VersionDefinition.services.forEach(function (service) {
+        services.push({
+          name: service.name,
+          version: service.versions[0].version,
+          components: service.versions[0].components
+        });
+      });
+      response.services = services;
+
+      // to display repos panel, should map all available operating systems including empty ones
+      this.getSupportedOSList(response.stackName, response.stackVersion).complete(function () {
+        var existedOS = data.operating_systems;
+        var existedMap = {};
+        existedOS.map(function (existedOS) {
+          existedOS.isSelected = true;
+          existedMap[existedOS.OperatingSystems.os_type] = existedOS;
+        });
+        self.get('allSupportedOS').forEach(function(supportedOS) {
+          if(!existedMap[supportedOS.OperatingSystems.os_type]) {
+            supportedOS.isSelected = false;
+            supportedOS.repositories.forEach(function(repo) {
+              repo.Repositories.base_url = '';
+            });
+            existedOS.push(supportedOS);
+          }
+        });
+        App.stackMapper.map(_data.resources, "VersionDefinition");
+        dataInfo.dfd.resolve(response);
+      });
+    }
+  },
+
+  /*
+   * Post version definition file (.xml) to server in step 8
+   */
+  postVersionDefinitionFileStep8: function (isXMLdata, data) {
+    var dfd = $.Deferred();
+    var name = isXMLdata == true? 'wizard.step8.post_version_definition_file.xml' : 'wizard.step8.post_version_definition_file';
+    App.ajax.send({
+      name: name,
+      sender: this,
+      data: {
+        dfd: dfd,
+        data: data
+      },
+      success: 'postVersionDefinitionFileStep8SuccessCallback',
+      error: 'postVersionDefinitionFileErrorCallback'
+    });
+    return dfd.promise();
+  },
+  /**
+   * onSuccess callback for postVersionDefinitionFile.
+   */
+  postVersionDefinitionFileStep8SuccessCallback: function (response, request, data) {
+    if (response.resources.length && response.resources[0].VersionDefinition) {
+      data.dfd.resolve(
+        {
+          stackName: response.resources[0].VersionDefinition.stack_name,
+          id: response.resources[0].VersionDefinition.id,
+          stackVersion: response.resources[0].VersionDefinition.stack_version
+        });
+    }
+  },
+
+  /**
+   * onError callback for postVersionDefinitionFile.
+   */
+  postVersionDefinitionFileErrorCallback: function (request, ajaxOptions, error, data, params) {
+    params.dfd.reject(data);
+    var header = Em.I18n.t('installer.step1.useLocalRepo.uploadFile.error.title');
+    var body = "";
+    if(request && request.responseText){
+      try {
+        var json = $.parseJSON(request.responseText);
+        body = json.message;
+      } catch (err) {}
+    }
+    App.showAlertPopup(header, body);
+  },
+
+  getSupportedOSList: function (stackName, stackVersion) {
+    return  App.ajax.send({
+      name: 'wizard.step1.get_supported_os_types',
+      sender: this,
+      data: {
+        stackName: stackName,
+        stackVersion: stackVersion
+      },
+      success: 'getSupportedOSListSuccessCallback',
+      error: 'getSupportedOSListErrorCallback'
+    });
+  },
+
+  /**
+   * onSuccess callback for getSupportedOSList.
+   */
+  getSupportedOSListSuccessCallback: function (response, request, data) {
+    if (response.operating_systems) {
+      this.set('allSupportedOS', response.operating_systems);
+    }
+  },
+
+  /**
+   * onError callback for getSupportedOSList
+   */
+  getSupportedOSListErrorCallback: function (request, ajaxOptions, error, data, params) {
+    var header = Em.I18n.t('installer.step1.useLocalRepo.getSurpottedOs.error.title');
+    var body = "";
+    if(request && request.responseText){
+      try {
+        var json = $.parseJSON(request.responseText);
+        body = json.message;
+      } catch (err) {}
+    }
+    App.showAlertPopup(header, body);
+  },
+
+  updateRepoOSInfo: function (repoToUpdate, repo) {
+    var deferred = $.Deferred();
+    var repoVersion = this.prepareRepoForSaving(repo);
+    App.ajax.send({
+      name: 'admin.stack_versions.edit.repo',
+      sender: this,
+      data: {
+        stackName: repoToUpdate.stackName,
+        stackVersion: repoToUpdate.stackVersion,
+        repoVersionId: repoToUpdate.id,
+        repoVersion: repoVersion
+      }
+    }).success(function() {
+      deferred.resolve([]);
+    }).error(function() {
+      deferred.resolve([]);
+    });
+    return deferred.promise();
+  },
+
+  /**
+   * transform repo data into json for
+   * saving changes to repository version
+   * @param {Em.Object} repo
+   * @returns {{operating_systems: Array}}
+   */
+  prepareRepoForSaving: function(repo) {
+    var repoVersion = { "operating_systems": [] };
+    repo.get('operatingSystems').forEach(function (os, k) {
+      repoVersion.operating_systems.push({
+        "OperatingSystems": {
+          "os_type": os.get("osType")
+        },
+        "repositories": []
+      });
+      os.get('repositories').forEach(function (repository) {
+        repoVersion.operating_systems[k].repositories.push({
+          "Repositories": {
+            "base_url": repository.get('baseUrl'),
+            "repo_id": repository.get('repoId'),
+            "repo_name": repository.get('repoName')
+          }
+        });
+      });
+    });
+    return repoVersion;
+  },
+
   /**
    * Check validation of the customized local urls
    */
   checkRepoURL: function (wizardStep1Controller) {
     var selectedStack = this.get('content.stacks').findProperty('isSelected', true);
     selectedStack.set('reload', true);
-    var nameVersionCombo = selectedStack.get('id');
+    var nameVersionCombo = selectedStack.get('stackNameVersion');
     var stackName = nameVersionCombo.split('-')[0];
     var stackVersion = nameVersionCombo.split('-')[1];
     var dfd = $.Deferred();
@@ -624,7 +920,9 @@ App.InstallerController = App.WizardController.extend({
 
           if (!stacksLoaded) {
             $.when.apply(this, this.loadStacksVersions()).done(function () {
-              dfd.resolve(stacksLoaded);
+              Em.run.later('sync', function() {
+                dfd.resolve(stacksLoaded);
+              }, 1000);
             });
           } else {
             dfd.resolve(stacksLoaded);

+ 36 - 4
ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js

@@ -231,7 +231,7 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage,
    */
   realStackUrl: function () {
     return App.get('apiPrefix') + '/clusters/' + App.get('clusterName') +
-      '/stack_versions?fields=*,repository_versions/*,repository_versions/operating_systems/repositories/*';
+      '/stack_versions?fields=*,repository_versions/*,repository_versions/operating_systems/OperatingSystems/*,repository_versions/operating_systems/repositories/*';
   }.property('App.clusterName'),
 
   /**
@@ -1325,11 +1325,12 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage,
    */
   prepareRepoForSaving: function(repo) {
     var repoVersion = { "operating_systems": [] };
-
+    var ambari_managed_repositories = !repo.get('useRedhatSatellite');
     repo.get('operatingSystems').forEach(function (os, k) {
       repoVersion.operating_systems.push({
         "OperatingSystems": {
-          "os_type": os.get("osType")
+          "os_type": os.get("osType"),
+          "ambari_managed_repositories": ambari_managed_repositories
         },
         "repositories": []
       });
@@ -1794,5 +1795,36 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage,
     newWindow = window.open();
     newWindow.document.write(output);
     newWindow.focus();
-  }
+  },
+
+  /**
+   * load version for services to display on Choose Servoces page
+   * should load from VersionDefinition endpoint
+   */
+  loadServiceVersionFromVersionDefinitions: function () {
+    return App.ajax.send({
+      name: 'cluster.load_current_repo_stack_services',
+      sender: this,
+      data: {
+        clusterName: App.clusterName
+      },
+      success: 'loadServiceVersionFromVersionDefinitionsSuccessCallback',
+      error: 'loadServiceVersionFromVersionDefinitionsErrorCallback'
+    });
+  },
+
+  serviceVersionsMap: {},
+  loadServiceVersionFromVersionDefinitionsSuccessCallback: function (jsonData) {
+    var rv = jsonData.items[0].repository_versions[0].RepositoryVersions;
+    var map = this.get('serviceVersionsMap');
+    if (rv) {
+      rv.stack_services.forEach(function (item) {
+        map[item.name] = item.versions[0];
+      });
+    }
+  },
+
+  loadServiceVersionFromVersionDefinitionsErrorCallback: function (request, ajaxOptions, error) {
+  },
+
 });

+ 7 - 1
ambari-web/app/controllers/main/service/add_controller.js

@@ -192,7 +192,13 @@ App.AddServiceController = App.WizardController.extend(App.AddSecurityConfigs, {
       this.setSkipSlavesStep(App.StackService.find().filterProperty('isSelected').filterProperty('isInstalled', false), 3);
     }
     this.set('serviceToInstall', null);
-    this.set('content.services', App.StackService.find());
+    var self = this;
+    this.loadServiceVersionFromVersionDefinitions().complete(function () {
+      self.set('content.services', App.StackService.find().forEach(function (item) {
+        // user the service version from VersionDefinition
+        Ember.set(item, 'serviceVersionDisplay', self.get('serviceVersionsMap')[item.get('serviceName')]);
+      }));
+    });
   },
 
   /**

+ 29 - 0
ambari-web/app/controllers/wizard.js

@@ -677,6 +677,35 @@ App.WizardController = Em.Controller.extend(App.LocalStorage, App.ThemesMappingM
   loadServiceComponentsErrorCallback: function (request, ajaxOptions, error) {
   },
 
+  /**
+   * load version for services to display on Choose Servoces page
+   * should load from VersionDefinition endpoint
+   */
+  loadServiceVersionFromVersionDefinitions: function () {
+    return App.ajax.send({
+      name: 'cluster.load_current_repo_stack_services',
+      sender: this,
+      data: {
+        clusterName: App.clusterName
+      },
+      success: 'loadServiceVersionFromVersionDefinitionsSuccessCallback',
+      error: 'loadServiceVersionFromVersionDefinitionsErrorCallback'
+      });
+  },
+
+  serviceVersionsMap: {},
+  loadServiceVersionFromVersionDefinitionsSuccessCallback: function (jsonData) {
+    var rv = jsonData.items[0].repository_versions[0].RepositoryVersions;
+    var map = this.get('serviceVersionsMap');
+    if (rv) {
+      rv.stack_services.forEach(function (item) {
+        map[item.name] = item.versions[0];
+      });
+    }
+  },
+  loadServiceVersionFromVersionDefinitionsErrorCallback: function (request, ajaxOptions, error) {
+  },
+
   /**
    * Load config groups from local DB
    */

+ 84 - 1
ambari-web/app/controllers/wizard/step1_controller.js

@@ -31,7 +31,90 @@ App.WizardStep1Controller = Em.Controller.extend({
 
   selectedStack: function() {
     return App.Stack.find().findProperty('isSelected');
-  }.property('content.stacks.@each.isSelected')
+  }.property('content.stacks.@each.isSelected'),
 
+  optionsToSelect: {
+    'usePublicRepo': {
+      index: 0,
+      isSelected: true
+    },
+    'useLocalRepo': {
+      index: 1,
+      isSelected: false,
+      'uploadFile': {
+        index: 0,
+        name: 'uploadFile',
+        file: '',
+        hasError: false,
+        isSelected: true
+      },
+      'enterUrl': {
+        index: 1,
+        name: 'enterUrl',
+        url: 'http://',
+        hasError: false,
+        isSelected: false
+      }
+    }
+  },
 
+  /**
+   * Used to set version definition file from FileUploader
+   * @method setVDFFile
+   * @param {string} vdf
+   */
+  setVDFFile: function (vdf) {
+    this.set("optionsToSelect.useLocalRepo.uploadFile.file", vdf);
+  },
+
+  /**
+   * Load selected file to current page content
+   */
+  readVersionInfo: function(){
+    var data = {};
+    var isXMLdata = false;
+    if (this.get("optionsToSelect.usePublicRepo.isSelected")) return;
+    if (this.get("optionsToSelect.useLocalRepo.isSelected") && this.get("optionsToSelect.useLocalRepo.enterUrl.isSelected")) {
+      var url = this.get("optionsToSelect.useLocalRepo.enterUrl.url");
+      data = {
+        "VersionDefinition": {
+          "version_url": url
+        }
+      };
+      App.db.setLocalRepoVDFData(url);
+    } else if (this.get("optionsToSelect.useLocalRepo.uploadFile.isSelected")) {
+      isXMLdata = true;
+      // load from file browser
+      data = this.get("optionsToSelect.useLocalRepo.uploadFile.file");
+      App.db.setLocalRepoVDFData(data);
+    }
+    var installerController = App.router.get('installerController');
+    var self = this;
+    installerController.postVersionDefinitionFile(isXMLdata, data).done(function (response) {
+      self.set('latestSelectedLocalRepoId', response.stackNameVersion + "-" + response.actualVersion);
+      // load successfully, so make this local stack repo as selectedStack
+      self.get('content.stacks').setEach('isSelected', false);
+      self.get('content.stacks').findProperty('id', response.stackNameVersion + "-" + response.actualVersion).set('isSelected', true);
+      Ember.run.next(function () {
+        $("[rel=skip-validation-tooltip]").tooltip({ placement: 'right'});
+        $("[rel=use-redhat-tooltip]").tooltip({ placement: 'right'});
+      });
+    });
+  },
+
+  /**
+   * On click handler for removing OS
+   */
+  removeOS: function(event) {
+    var osToRemove = event.context;
+    Em.set(osToRemove, 'isSelected', false);
+  },
+
+  /**
+   * On click handler for adding new OS
+   */
+  addOS: function(event) {
+    var osToAdd = event.context;
+    Em.set(osToAdd, 'isSelected', true);
+  }
 });

+ 31 - 3
ambari-web/app/controllers/wizard/step8_controller.js

@@ -18,6 +18,7 @@
 
 var App = require('app');
 var stringUtils = require('utils/string_utils');
+var validator = require('utils/validator');
 
 App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wizardDeployProgressControllerMixin, App.ConfigOverridable, App.ConfigsSaverMixin, {
 
@@ -827,11 +828,38 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
       this.addRequestToAjaxQueue(ajaxOpts);
     }
   },
+
   /**
-   * Start deploy process
+   * To Start deploy process
    * @method startDeploy
    */
   startDeploy: function () {
+    if (this.get('content.controllerName') !== 'installerController') {
+      this._startDeploy();
+    } else {
+      var installerController = App.router.get('installerController');
+      var versionData = installerController.getSelectedRepoVersionData();
+      if (versionData) {
+        var self = this;
+        installerController.postVersionDefinitionFileStep8(versionData.isXMLdata, versionData.data).done(function (versionInfo) {
+          if (versionInfo.id && versionInfo.stackName && versionInfo.stackVersion) {
+            var selectedStack = App.Stack.find().findProperty('isSelected', true);
+            installerController.updateRepoOSInfo(versionInfo, selectedStack).done(function() {
+              self._startDeploy();
+            });
+          }
+        });
+      } else {
+        this._startDeploy();
+      }
+    }
+  },
+
+  /**
+   * Start deploy process
+   * @method startDeploy
+   */
+  _startDeploy: function () {
     this.createCluster();
     this.createSelectedServices();
     if (this.get('content.controllerName') !== 'addHostController') {
@@ -877,10 +905,11 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
   createCluster: function () {
     if (this.get('content.controllerName') !== 'installerController') return;
     var stackVersion = (this.get('content.installOptions.localRepo')) ? App.currentStackVersion.replace(/(-\d+(\.\d)*)/ig, "Local$&") : App.currentStackVersion;
+    var selectedStack = App.Stack.find().findProperty('isSelected', true);
     this.addRequestToAjaxQueue({
       name: 'wizard.step8.create_cluster',
       data: {
-        data: JSON.stringify({ "Clusters": {"version": stackVersion }})
+        data: JSON.stringify({ "Clusters": {"version": stackVersion, "repository_version": selectedStack.get('repositoryVersion')}})
       },
       success: 'createClusterSuccess'
     });
@@ -1274,7 +1303,6 @@ App.WizardStep8Controller = Em.Controller.extend(App.AddSecurityConfigs, App.wiz
     var masterHosts = this.get('content.masterComponentHosts');
 
     // add all components with cardinality == ALL of selected services
-
     var registeredHosts = this.getRegisteredHosts();
     var notInstalledHosts = registeredHosts.filterProperty('isInstalled', false);
     this.get('content.services').filterProperty('isSelected').forEach(function (service) {

+ 13 - 0
ambari-web/app/mappers/repository_version_mapper.js

@@ -34,6 +34,7 @@ App.repoVersionMapper = App.QuickDataMapper.create({
       upgrade_pack: repoVersionsKey + '.upgrade_pack',
       stack_version_type: repoVersionsKey + '.stack_name',
       stack_version_number: repoVersionsKey + '.stack_version',
+      use_redhat_satellite: 'use_redhat_satellite',
       services_key: 'services',
       services_type: 'array',
       services: {
@@ -128,7 +129,19 @@ App.repoVersionMapper = App.QuickDataMapper.create({
               serviceArray.pushObject(serviceObj);
               resultService.push(this.parseIt(serviceObj, this.get('modelService')));
             }, this);
+          } else if (item[repoVersionsKey].stack_services) {
+            item[repoVersionsKey].stack_services.forEach(function (service) {
+              var serviceObj = {
+                id: service.name,
+                name: service.name,
+                display_name: service.display_name,
+                latest_version: service.versions[0] ? service.versions[0]: ''
+              };
+              serviceArray.pushObject(serviceObj);
+              resultService.push(this.parseIt(serviceObj, this.get('modelService')));
+            }, this);
           }
+          repo.use_redhat_satellite = item.operating_systems[0].OperatingSystems.ambari_managed_repositories === false;
           repo.operating_systems = osArray;
           repo.services = serviceArray;
           resultRepoVersion.push(this.parseIt(repo, this.modelRepoVersion(isCurrentStackOnly)));

+ 44 - 9
ambari-web/app/mappers/stack_mapper.js

@@ -21,11 +21,15 @@ App.stackMapper = App.QuickDataMapper.create({
   modelStack: App.Stack,
   modelOS: App.OperatingSystem,
   modelRepo: App.Repository,
+  modelServices: App.ServiceSimple,
   
   configStack: {
     id: 'id',
     stack_name: 'stack_name',
     stack_version: 'stack_version',
+    show_available: 'show_available',
+    type: 'type',
+    repository_version: 'repository_version',
     active: 'active',
     parent_stack_version: 'parent_stack_version',
     min_upgrade_version: 'min_upgrade_version',
@@ -33,6 +37,11 @@ App.stackMapper = App.QuickDataMapper.create({
     max_jdk_version: 'max_jdk',
     is_selected: 'is_selected',
     config_types: 'config_types',
+    stack_services_key: 'stack_services',
+    stack_services_type: 'array',
+    stack_services: {
+      item: 'id'
+    },
     operating_systems_key: 'operating_systems',
     operating_systems_type: 'array',
     operating_systems: {
@@ -46,12 +55,20 @@ App.stackMapper = App.QuickDataMapper.create({
     stack_name: 'stack_name',
     stack_version: 'stack_version',
     stack_id: 'stack_id',
+    is_selected: 'is_selected',
     repositories_key: 'repositories',
     repositories_type: 'array',
     repositories: {
       item: 'id'
     }
   },
+
+  configService: {
+    id: 'id',
+    name: 'name',
+    display_name: 'display_name',
+    latest_version: 'latest_version'
+  },
   
   configRepository: {
     id: 'id',
@@ -67,42 +84,59 @@ App.stackMapper = App.QuickDataMapper.create({
     operating_system_id: 'os_id'
   },
   
-  map: function(json) {
+  map: function(json, key) {
     var modelStack = this.get('modelStack');
     var modelOS = this.get('modelOS');
     var modelRepo = this.get('modelRepo');
+    var modelServices = this.get('modelServices');
     var resultStack = [];
     var resultOS = [];
     var resultRepo = [];
+    var resultServices = [];
 
-    var stackVersions = json.items.filterProperty('Versions.active');
-    stackVersions.sortProperty('Versions.stack_version').reverse().forEach(function(item) {
-      var stack = item.Versions;
+    var stackVersions = json;
+    var propertiesKey = key;
+    stackVersions.sortProperty(key + '.stack_version').reverse().forEach(function(item) {
+      var stack = item[key];
       var operatingSystemsArray = [];
+      var servicesArray = [];
 
-      stack.id = stack.stack_name + "-" + stack.stack_version;
+      stack.id = stack.stack_name + "-" + stack.stack_version + "-" + stack.repository_version; //HDP-2.5-2.5.0.0
 
       item.operating_systems.forEach(function(ops) {
         var operatingSystems = ops.OperatingSystems;
 
         var repositoriesArray = [];
         ops.repositories.forEach(function(repo) {
-          repo.Repositories.id = [repo.Repositories.stack_name, repo.Repositories.stack_version, repo.Repositories.os_type, repo.Repositories.repo_id].join('-');
-          repo.Repositories.os_id = [repo.Repositories.stack_name, repo.Repositories.stack_version, repo.Repositories.os_type].join('-');
+          repo.Repositories.id = [stack.id, repo.Repositories.os_type, repo.Repositories.repo_id].join('-');
+          repo.Repositories.os_id = [stack.id, repo.Repositories.os_type].join('-');
+          if (!repo.Repositories.latest_base_url)  repo.Repositories.latest_base_url = repo.Repositories.base_url;
           resultRepo.push(this.parseIt(repo.Repositories, this.get('configRepository')));
           repositoriesArray.pushObject(repo.Repositories);
         }, this);
 
 
-        operatingSystems.id = operatingSystems.stack_name + "-" + operatingSystems.stack_version + "-" + operatingSystems.os_type;
+        operatingSystems.id = stack.id + "-" + operatingSystems.os_type;
         operatingSystems.stack_id = operatingSystems.stack_name + "-" + operatingSystems.stack_version;
         operatingSystems.repositories = repositoriesArray;
+        operatingSystems.is_selected = (ops.isSelected == true || ops.isSelected == undefined);
         resultOS.push(this.parseIt(operatingSystems, this.get('configOS')));
         operatingSystemsArray.pushObject(operatingSystems);
         
       }, this);
-      
 
+      stack.stack_services.forEach(function(service) {
+        var serviceObj = {
+          id: service.name + '-' + stack.id,
+          name: service.name,
+          display_name: service.display_name,
+          latest_version: service.versions? service.versions[0] : ''
+        };
+        resultServices.push(this.parseIt(serviceObj, this.get('configService')));
+        servicesArray.pushObject(serviceObj);
+      }, this);
+
+      stack.stack_services = servicesArray;
       stack.operating_systems = operatingSystemsArray;
       resultStack.push(this.parseIt(stack, this.get('configStack')));
       
@@ -111,6 +145,7 @@ App.stackMapper = App.QuickDataMapper.create({
     App.store.commit();
     App.store.loadMany(modelRepo, resultRepo);
     App.store.loadMany(modelOS, resultOS);
+    App.store.loadMany(modelServices, resultServices);
     App.store.loadMany(modelStack, resultStack);
   }
 });

+ 30 - 2
ambari-web/app/messages.js

@@ -549,8 +549,36 @@ Em.I18n.translations = {
   'installer.step0.clusterName.error.whitespace':'Cluster Name cannot contain whitespace',
   'installer.step0.clusterName.error.specialChar':'Cluster Name cannot contain special characters',
 
-  'installer.step1.header':'Select Stack',
-  'installer.step1.body':'Please select the service stack that you want to use to install your Hadoop cluster.',
+  'installer.step1.header':'Select Version',
+  'installer.step1.body':'Select the software version and method of delivery for your cluster. Using a Public Repository requires Internet connectivity. Using a Local Repository requires you have configured the software in a repository available in your network.',
+  'installer.step1.selectUseRepoOptions.public':'Use Public Repository',
+  'installer.step1.selectUseRepoOptions.public.networkLost.button':'Not Available',
+  'installer.step1.selectUseRepoOptions.public.networkLost':'Why is this disabled?',
+  'installer.step1.selectUseRepoOptions.public.networkLost.popup.title': 'Public Repository Option Disabled',
+  'installer.step1.selectUseRepoOptions.public.networkLost.popup.msg': 'Ambari does not have access to the Internet and cannot use the Public Repository for installing the software. Your Options:',
+  'installer.step1.selectUseRepoOptions.public.networkLost.popup.msg1': 'Configure your hosts for access to the Internet.',
+  'installer.step1.selectUseRepoOptions.public.networkLost.popup.msg2': 'If you are using an Internet Proxy, refer to the Ambari Documentation on how to configure Ambari to use the Internet Proxy.',
+  'installer.step1.selectUseRepoOptions.public.networkLost.popup.msg3': 'Use the Local Repositoy option.',
+  'installer.step1.selectUseRepoOptions.public.select':'Select Version',
+  'installer.step1.selectUseRepoOptions.local':'Use Local Repository',
+  'installer.step1.usePublicRepo.ReposList.empty':'No other repositories',
+  'installer.step1.usePublicRepo.viewRepos':'View Repositories',
+  'installer.step1.useLocalRepo.uploadFile': 'Upload Version Definition File',
+  'installer.step1.useLocalRepo.uploadFile.error.title': 'Upload Version Definition File Error',
+  'installer.step1.useLocalRepo.getSurpottedOs.error.title': 'Cannot get supportted OS types',
+  'installer.step1.useLocalRepo.addRepo.button': 'Add Repository',
+  'installer.step1.useLocalRepo.enterUrl': 'Version Definition File URL',
+  'installer.step1.useLocalRepo.readButton': 'Read Version Info',
+  'installer.step1.useLocalRepo.infoForm.details.title': 'Details',
+  'installer.step1.useLocalRepo.infoForm.details.stackName': 'Stack Name',
+  'installer.step1.useLocalRepo.infoForm.details.displayName': 'Display Name',
+  'installer.step1.useLocalRepo.infoForm.details.version': 'Version',
+  'installer.step1.useLocalRepo.infoForm.details.actualVersion': 'Actual Version',
+  'installer.step1.useLocalRepo.infoForm.details.releaseNotes': 'Release Notes',
+  'installer.step1.useLocalRepo.infoForm.content.title': 'Contents',
+  'installer.step1.useLocalRepo.infoForm.content.empty': 'No contents to display',
+  'installer.step1.useLocalRepo.infoForm.alert.baseUrl': 'Provide Base URLs for the Operating Systems you are configuring.',
+  'installer.step1.useLocalRepo.infoForm.alert.warning': 'Some of the repositories failed validation. Make changes to the base url or skip validation if you are sure that urls are correct',
   'installer.step1.advancedRepo.title':'Advanced Repository Options',
   'installer.step1.advancedRepo.message':'Customize the repository Base URLs for downloading the Stack software packages. If your hosts do not have access to the internet, you will have to create a local mirror of the Stack repository that is accessible by all hosts and use those Base URLs here.',
   'installer.step1.advancedRepo.importantMassage':'<b>Important:</b> When using local mirror repositories, you only need to provide Base URLs for the Operating System you are installing for your Stack. Uncheck all other repositories.',

+ 20 - 31
ambari-web/app/models/stack.js

@@ -19,18 +19,29 @@
 var App = require('app');
 
 App.Stack = DS.Model.extend({
-  id: DS.attr('string'), //  ${stackName}-${stackVersion}.
+  id: DS.attr('string'), //  ${stackName}-${stackVersion}-${repoVersion}.
   stackName: DS.attr('string'),
   stackVersion: DS.attr('string'),
-  active: DS.attr('boolean'),  // All of the instances should have this value to true. We should map only those stacks that has active flag set to true
-  parentStackVersion: DS.attr('string'),
-  minUpgradeVersion: DS.attr('string'),
-  minJdkVersion: DS.attr('string'),
-  maxJdkVersion: DS.attr('string'),
-  configTypes: DS.attr('object'),
+  repositoryVersion: DS.attr('string'),
+  showAvailable: DS.attr('boolean'),  // All of the instances should have this value to true. We should map only those stacks that has this flag set to true
+  type: DS.attr('string'), // ["PATCH", "STANDARD"]
+  stackServices: DS.hasMany('App.ServiceSimple'),
   operatingSystems: DS.hasMany('App.OperatingSystem'),
   isSelected: DS.attr('boolean', {defaultValue: false}),
 
+  stackNameVersion: function () {
+    //${stackName}-${stackVersion}.
+    return this.get('stackName') + '-' + this.get('stackVersion');
+  }.property('stackName', 'stackVersion'),
+
+  isPatch: function () {
+    return this.get('type') == "PATCH";
+  }.property('type'),
+  displayName: function () {
+    //${stackName}-${repositoryVersion}.
+    return this.get('stackName') + '-' + this.get('repositoryVersion');
+  }.property('stackName', 'repositoryVersion'),
+
   /**
    * @return: {Array} returns supported repositories for all OperatingSystem's supported by a stack instance
    */
@@ -43,30 +54,8 @@ App.Stack = DS.Model.extend({
       }, this);
     }, this);
     return repositories;
-  }.property('id'),
-
-  /**
-   * @return: {Array} App.StackService instances for selected stack instance. For non-selected stack instance returns empty array
-   */
-  services: function () {
-    var result = [];
-    var isStackSelected = this.get('isSelected');
-    var stackServices = App.StackService.find().get('length');
-    if (isStackSelected && stackServices) {
-      result = App.StackService.find();
-    }
-    return result;
-  }.property('isSelected'),
-
-  /**
-   * Right now there ambari-web is not fetching this information from the server as it does not need as of present.
-   * @TODO: This should return stack level configurations for selected stack instance i.e properties of cluster-env file
-   */
-  configurations: function() {
-    return [];
-  }.property('isSelected')
-
+  }.property('id')
 });
 
 
-App.Stack.FIXTURES = [];
+App.Stack.FIXTURES = [];

+ 1 - 0
ambari-web/app/models/stack_version/repository_version.js

@@ -25,6 +25,7 @@ App.RepositoryVersion = DS.Model.extend({
   upgradePack: DS.attr('string'),
   stackVersionType: DS.attr('string'),
   stackVersionNumber: DS.attr('string'),
+  useRedhatSatellite: DS.attr('boolean'),
   operatingSystems: DS.hasMany('App.OS'),
   services: DS.hasMany('App.ServiceSimple'),
   stackVersion: DS.belongsTo('App.StackVersion'),

+ 8 - 1
ambari-web/app/routes/add_service_routes.js

@@ -102,7 +102,14 @@ module.exports = App.WizardRoute.extend({
         controller.loadAllPriorSteps().done(function () {
           var wizardStep4Controller = router.get('wizardStep4Controller');
           wizardStep4Controller.set('wizardController', controller);
-          controller.connectOutlet('wizardStep4', controller.get('content.services').filterProperty('isInstallable', true));
+          controller.loadServiceVersionFromVersionDefinitions().complete(function () {
+            controller.set('content.services', App.StackService.find().forEach(function (item) {
+              // user the service version from VersionDefinition
+              Ember.set(item, 'serviceVersionDisplay', controller.get('serviceVersionsMap')[item.get('serviceName')]);
+              //item.set('serviceVersionDisplay', controller.get('serviceVersionsMap')[item.get('serviceName')]);
+            }));
+            controller.connectOutlet('wizardStep4', controller.get('content.services').filterProperty('isInstallable', true));
+          });
         });
       });
     },

+ 155 - 0
ambari-web/app/styles/application.less

@@ -6201,6 +6201,161 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox {
   margin-left: -10px;
 }
 
+#select-stack .stack-version-selection{
+  .select-version-label {
+    padding: 5px 25px;
+  }
+  .right-stack-info {
+    margin-left: 0px;
+    .available-repos-dropdown {
+      a, a.disbled{
+        cursor: pointer;
+      }
+      a.disabled{
+        color: #999999;
+        background: none;
+      }
+    }
+  }
+}
+#select-stack .stack-version-selection.disabled{
+  .select-version-label {
+    color: #999999;
+  }
+  .btn-primary.disabled:hover{
+    cursor: not-allowed;
+  }
+}
+
+.public-disabled-message {
+  padding: 5px;
+}
+.public-disabled-option {
+  padding: 5px;
+  padding-left: 15px;
+}
+#select-stack {
+  .big-radio {
+    font-weight: bold;
+    padding: 5px 15px;
+  }
+  #public-disabled-link {
+    margin-left: 10px;
+    font-weight: normal;
+    cursor: pointer;
+  }
+  #upload-definition-file-panel {
+    .register-version-options {
+      padding: 5px 0px;
+      .local-option-label {
+        margin-left: 20px;
+        padding-top: 4px;
+      }
+    }
+    .vdf-url {
+      input {
+        width: 80%;
+      }
+    }
+    .read-info-button {
+      margin: 10px 0px;
+    }
+  }
+  #upload-definition-file-panel.disabled {
+     .local-option-label {
+       color: #999999;
+     }
+  }
+}
+#select-stack #repoVersionInfoForm {
+  .accordion-heading {
+    background-color: #f0f0f0;
+    font-weight: bold;
+    p {
+      margin-bottom: 0px;
+      display: block;
+      padding: 8px 15px;
+    }
+  }
+  .accordion-body {
+    .version-info-section {
+      padding: 10px;
+    }
+    .control-label {
+      text-align: left;
+      line-height: 14px;
+    }
+    .version-info {
+      font-weight: bold;
+      padding-top: 5px;
+      line-height: 14px;
+    }
+  }
+  .details-panel .patch-icon {
+    color: #ff4500;
+  }
+  .details-panel .version-contents-section {
+    border: 1px solid #ddd;
+    max-height: 200px;
+    overflow: auto;
+    padding: 8px 25px;
+    margin: 8px;
+  }
+  .repos-panel {
+    .remove-icon {
+      color: red;
+      margin: 20px 0px;
+      padding: 0px;
+      text-align: center;
+      cursor: pointer;
+    }
+    .border-bottom {
+      border-bottom: 1px solid #ebebeb;
+    }
+    .repo-table-title {
+      padding-left: 5px;
+      border-bottom: 1px solid #ebebeb;
+      label {
+        font-weight: bold;
+      }
+    }
+    .os-type-label {
+      margin-top: 27px;
+      padding-left: 10px;
+      label {
+        font-weight: bold;
+      }
+    }
+    .repo-name-label {
+      text-align: left;
+      padding-top: 10px;
+    }
+    .repo-name-url {
+      padding: 8px 0px;
+    }
+    .repo-url input {
+      width: 90%;
+      height: 24px;
+    }
+    .add-os-button {
+      margin-top:10px;
+      button.disabled {
+        cursor: not-allowed;
+      }
+    }
+    #skip-validation {
+      margin-top: 13px;
+    }
+    #use-redhat, #skip-validation {
+      .icon-question-sign {
+        color: #0572ff;
+      }
+      input{
+        margin: 0px 10px;
+      }
+    }
+  }
+}
 #combo_search_box {
   .VS-search {
     .VS-search-box {

+ 1 - 1
ambari-web/app/templates/main/admin/stack_upgrade/edit_repositories.hbs

@@ -51,7 +51,7 @@
        data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.skipValidation.tooltip"}}></i></label>
 </div>
 <div id="use-redhat">
-  <label>{{view Ember.Checkbox classNames="align-checkbox" checkedBinding="view.parentView.useRedhatSatellite"}}{{t installer.step1.advancedRepo.useRedhatSatellite.message}}
+  <label>{{view Ember.Checkbox classNames="align-checkbox" checkedBinding="view.content.useRedhatSatellite"}}{{t installer.step1.advancedRepo.useRedhatSatellite.message}}
     <i class="icon-question-sign" rel="use-redhat-tooltip"
        data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.useRedhatSatellite.tooltip"}}></i></label>
 </div>

+ 1 - 1
ambari-web/app/templates/main/admin/stack_upgrade/services.hbs

@@ -30,7 +30,7 @@
     {{#each service in view.services}}
     <tr>
       <td class="service-display-name">{{service.displayName}}</td>
-      <td class="service-stack-version">{{service.serviceVersion}}</td>
+      <td class="service-stack-version">{{service.serviceVersionDisplay}}</td>
       <td class="stack-version-state">
         {{#if service.isInstalled}}
           <span class="label label-success">{{t common.installed}}</span>

+ 5 - 5
ambari-web/app/templates/main/admin/stack_upgrade/versions.hbs

@@ -17,6 +17,11 @@
 }}
 
 <div id="versions-filter-section">
+  {{#isAuthorized "AMBARI.MANAGE_STACK_VERSIONS"}}
+    <button class="btn btn-primary" {{action goToVersions target="view"}} id="manage-versions-link">
+        <i class="icon-external-link"></i>&nbsp;{{t admin.stackVersions.manageVersions}}
+    </button>
+  {{/isAuthorized}}
   <div class="btn-group display-inline-block">
     <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
       <span class="filters-label">{{t common.filter}}: </span>
@@ -35,11 +40,6 @@
       {{/each}}
     </ul>
   </div>
-  {{#isAuthorized "AMBARI.MANAGE_STACK_VERSIONS"}}
-    <button class="btn btn-primary pull-right" {{action goToVersions target="view"}} id="manage-versions-link">
-      <i class="icon-external-link"></i>&nbsp;{{t admin.stackVersions.manageVersions}}
-    </button>
-  {{/isAuthorized}}
 </div>
 <div id="versions-section" class="row-fluid">
   <div class="span2 left-menu-table">

+ 170 - 89
ambari-web/app/templates/wizard/step1.hbs

@@ -17,109 +17,190 @@
 }}
 <div id="select-stack">
   <h2>{{t installer.step1.header}}</h2>
-  <p class="alert alert-info">
-    {{t installer.step1.body}}
-  </p>
-  <p><b>{{t common.stacks}}</b></p>
-  <form autocomplete="off">
-    {{#each stack in view.stacks}}
-      <label class="radio">{{view view.stackRadioButton contentBinding="stack"}} {{stack.name}}</label>
-    {{/each}}
-  </form>
+  <p class="alert alert-info">{{t installer.step1.body}}</p>
 
+  <label class="radio big-radio">{{view view.usePublicRepoRadioButton}} {{t installer.step1.selectUseRepoOptions.public}}
+      {{#unless view.selectedPublicRepoVersion}}
+          <a id="public-disabled-link" {{action "openPublicOptionDisabledWindow" target="view"}}>{{t installer.step1.selectUseRepoOptions.public.networkLost}}</a>
+      {{/unless}}
+  </label>
 
-  <div class="accordion" id="advancedRepoAccordion">
-    <div class="accordion-group">
-      <div class="accordion-heading" {{action "onToggleBlock" target="view"}}>
-        <i {{bindAttr class=":pull-left :accordion-toggle view.isRLCollapsed:icon-caret-right:icon-caret-down"}}></i>
-        <a class="accordion-toggle">
-          {{t installer.step1.advancedRepo.title}}
-          {{#if view.showErrorsWarningCount}}
-            <span class="badge badge-important">{{view.totalErrorCnt}}</span>
+    <form {{bindAttr class="optionsToSelect.useLocalRepo.isSelected:disabled :stack-version-selection :row-fluid"}}>
+      <div class="span3 select-version-label">
+        {{t installer.step1.selectUseRepoOptions.public.select}}
+      </div>
+      <div class="span7 right-stack-info">
+        <div class="repo-list-button btn-group">
+          {{#if view.selectedPublicRepoVersion}}
+            <button type="button" {{bindAttr class="optionsToSelect.useLocalRepo.isSelected:disabled :btn :btn-primary :dropdown-toggle"}} data-toggle="dropdown">
+              {{view.selectedPublicRepoVersion.displayName}} &nbsp;<span class="caret"></span>
+            </button>
+          {{else}}
+            <button type="button" class="disabled btn btn-primary dropdown-toggle"}} data-toggle="dropdown">
+             {{t installer.step1.selectUseRepoOptions.public.networkLost.button}}
+            </button>
           {{/if}}
-        </a>
+          <ul class="dropdown-menu available-repos-dropdown">
+            {{#if view.availableStackRepoList}}
+              {{#each repo in view.availableStackRepoList}}
+                {{#if repo.repositoryVersion}}
+                  <li><a {{action "selectRepoInList" repo target="view"}}>{{repo.displayName}}</a></li>
+                {{/if}}
+              {{/each}}
+            {{else}}
+              <li><a class="disabled">{{t installer.step1.usePublicRepo.ReposList.empty}}</a></li>
+            {{/if}}
+          </ul>
+        </div>
       </div>
-      <div class="accordion-body collapse in">
-        <div class="accordion-inner">
-          <div class="alert alert-info">{{t installer.step1.advancedRepo.message}}</div>
-          <div class="alert alert-warning">{{t installer.step1.advancedRepo.importantMassage}}</div>
+    </form>
 
-          <div class="repositories-table">
-            <div class="thead">
-              <div class="first-th">&nbsp;</div>
-              <div class="th os-th">{{t common.os}}</div>
-              <div class="th name-th">{{t common.name}}</div>
-              <div class="th url-th">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</div>
+    {{!--Local repo loaded info below--}}
+  <label class="radio big-radio">{{view view.useLocalRepoRadioButton}} {{t installer.step1.selectUseRepoOptions.local}}</label>
+
+    <div id="upload-definition-file-panel" {{bindAttr class="optionsToSelect.usePublicRepo.isSelected:disabled"}}>
+      <div class="clearfix register-version-options row-fluid">
+        <div class="span5 option-radio-button">
+          <label class="local-option-label radio">
+            {{view view.uploadFileRadioButton}} {{t installer.step1.useLocalRepo.uploadFile}}
+          </label>
+        </div>
+        <div class="span7">
+          {{#if view.isFileApi}}
+            {{view App.VersionDefinitionFileUploader disabledBinding="view.fileBrowserDisabled"}}
+          {{/if}}
+        </div>
+      </div>
+      <div class="clearfix register-version-options row-fluid">
+        <div class="span5 option-radio-button">
+          <label class="local-option-label radio">
+            {{view view.enterUrlRadioButton}} {{t installer.step1.useLocalRepo.enterUrl}}
+          </label>
+        </div>
+        <div class="span7 vdf-url">
+          <div {{bindAttr class="optionsToSelect.useLocalRepo.enterUrl.name optionsToSelect.useLocalRepo.enterUrl.url.hasError:has-error }"}}>
+            {{view Ember.TextField valueBinding="optionsToSelect.useLocalRepo.enterUrl.url" disabledBinding="view.enterUrlFieldDisabled"}}
+          </div>
+        </div>
+        <div class="span12 read-info-button">
+          <button {{bindAttr class="view.readInfoButtonDisabled:disabled :btn :btn-primary :pull-right"}}
+            {{action "readVersionInfo" target="controller"}}> {{t installer.step1.useLocalRepo.readButton}}</button>
+        </div>
+      </div>
+    </div>
+
+    <form id="repoVersionInfoForm" class="form-horizontal" role="form" name="localVersionInfoForm" novalidate>
+      <div class="accordion-group details-panel">
+        <div class="accordion-heading">
+          <p>{{t installer.step1.useLocalRepo.infoForm.details.title}}</p>
+        </div>
+        <div class="accordion-body">
+          <div class="accordion-inner">
+            <div class="row-fluid">
+              <div class="span5 version-info-section">
+                <div class="row-fluid">
+                  <label class="control-label span5">{{t installer.step1.useLocalRepo.infoForm.details.stackName}}</label>
+                  <div class="version-info span5">{{controller.selectedStack.stackNameVersion}}</div>
+                  {{#if controller.selectedStack.isPatch}}
+                      <div class="span2 patch-icon"><i class="icon-umbrella"></i>&nbsp;{{t common.patch}}</div>
+                  {{/if}}
+                </div>
+                <div class="row-fluid">
+                  <label class="control-label span5">{{t installer.step1.useLocalRepo.infoForm.details.displayName}}</label>
+                  <div class="version-info span7">{{controller.selectedStack.displayName}}</div>
+                </div>
+                <div class="row-fluid">
+                  <label class="control-label span5">{{t installer.step1.useLocalRepo.infoForm.details.version}}</label>
+                  <div class="version-info span7">{{controller.selectedStack.repositoryVersion}}</div>
+                </div>
+              </div>
+              <div class="span6 version-contents-section">
+                {{#unless view.selectedServices}}
+                  <div class="alert alert-info" role="alert">{{t installer.step1.useLocalRepo.infoForm.content.empty}}</div>
+                {{/unless}}
+                {{#each service in view.selectedServices}}
+                  <div class="clearfix row-fluid">
+                      <div class="version-info span10">{{service.displayName}} ({{service.version}})</div>
+                  </div>
+                {{/each}}
+              </div>
             </div>
-            <div class="tbody">
+          </div>
+        </div>
+      </div>
+      <div class="accordion-group repos-panel">
+        <div class="accordion-heading">
+          <p>{{t common.repositories}}</p>
+        </div>
+          <div class="accordion-body version-contents-body">
+            <div class="accordion-inner">
+              <div class="alert alert-info" role="alert">{{t installer.step1.useLocalRepo.infoForm.alert.baseUrl}}</div>
+              {{#if view.hasValidationErrors}}
+                <div class="alert alert-warning" role="alert">{{t installer.step1.useLocalRepo.infoForm.alert.warning}}</div>
+              {{/if}}
+
+              <div class="clearfix repo-table-title row-fluid">
+                <div class="span2"><label>{{t common.os}}</label></div>
+                <div class="span2"><label>{{t common.name}}</label></div>
+                <div class="span7"><label>{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</label></div>
+              </div>
+
               {{#each operatingSystem in view.operatingSystems}}
-                <div class="trow">
-                  <div {{bindAttr class=":os-td operatingSystem.osType"}}>
-                    <label>
-                      {{view Ember.Checkbox checkedBinding="operatingSystem.isSelected"}}
-                      <span {{bindAttr class=":os operatingSystem.isSelected::disabled-label"}}>{{operatingSystem.osType}}</span>
-                    </label>
-                  </div>
-                  <div style="width:83%">
-                    {{#each repository in operatingSystem.repositories}}
-                      <div class="sub-trow">
-                        <div class="name-td">{{repository.repoId}}</div>
-                        <div class="validation-td">
-                          {{#if repository.validation}}
-                            {{view view.popoverView repositoryBinding="repository"}}
-                          {{/if}}
-                        </div>
-                        <div {{bindAttr class=":url-td operatingSystem.osType repository.repoId repository.invalidFormatError:textfield-error repository.invalidError:textfield-error"}}>
-                          {{view Ember.TextField valueBinding="repository.baseUrl" disabledBinding="operatingSystem.isDeselected"}}
-                        </div>
-                        <div class="clear-td">
-                          {{#if repository.clearAll}}
-                            <a {{action "clearGroupLocalRepository" repository target="view" }} {{bindAttr class="operatingSystem.isSelected::disabled-clear-button"}}>
-                              <i class="icon-remove-sign"></i>
-                            </a>
-                          {{/if}}
+                {{#if operatingSystem.isSelected}}
+                  <div class="clearfix row-fluid border-bottom">
+                    <div class="span2 os-type-label">
+                      <label>{{operatingSystem.osType}}</label>
+                    </div>
+                    <div class="span9">
+                      {{#each repository in operatingSystem.repositories}}
+                        <div class="repo-name-url row-fluid" {{bindAttr class="repository.hasError:has-error"}} >
+                          <label class="repo-name-label control-label span3">{{repository.repoId}}</label>
+                          <div class="validation-td span1">
+                            {{#if repository.validation}}
+                                {{view view.popoverView repositoryBinding="repository"}}
+                            {{/if}}
+                          </div>
+                          <div {{bindAttr class=":span8 :repo-url repository.invalidFormatError:textfield-error repository.invalidError:textfield-error"}}>
+                            {{view Ember.TextField valueBinding="repository.baseUrl"}}
+                          </div>
                         </div>
-                        <div class="actions-td">
-                          {{#if repository.undo}}
-                            <a {{action "undoGroupLocalRepository" repository target="view" }}>
-                              <i class="icon-undo"></i>{{t common.undo}}
-                            </a>
-                          {{/if}}
-                        </div>
-                      </div>
-                    {{/each}}
+                      {{/each}}
+                    </div>
+                    <div class="span1 remove-icon" {{action "removeOS" operatingSystem target="controller"}}><i class="icon-minus"></i>{{t common.remove}}</div>
                   </div>
-                </div>
+                {{/if}}
               {{/each}}
+
+              <div class="add-os-button btn-group pull-right">
+                <button {{bindAttr class=":btn :dropdown-toggle view.isAddOsButtonDisabled:disabled"}} data-toggle="dropdown">
+                  <i class="icon-plus"></i> {{t common.add}} &nbsp;<span class="caret"></span>
+                </button>
+                <ul class="dropdown-menu">
+                  {{#each operatingSystem in view.operatingSystems}}
+                    {{#unless operatingSystem.isSelected}}
+                      <li><a {{action "addOS" operatingSystem target="controller"}}>{{operatingSystem.osType}}</a></li>
+                    {{/unless}}
+                  {{/each}}
+                </ul>
+              </div>
+              <div id="skip-validation">
+                <label>{{view Ember.Checkbox checkedBinding="skipValidationChecked" class="checkbox"}}{{t installer.step1.advancedRepo.skipValidation.message}}
+                  <i class="icon-question-sign" rel="skip-validation-tooltip"
+                     data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.skipValidation.tooltip"}}></i></label>
+              </div>
+              <div id="use-redhat">
+                <label>{{view Ember.Checkbox classNames="align-checkbox" checkedBinding="useRedhatSatellite"}}{{t installer.step1.advancedRepo.useRedhatSatellite.message}}
+                  <i class="icon-question-sign" rel="use-redhat-tooltip"
+                    data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.useRedhatSatellite.tooltip"}}>
+                  </i>
+                </label>
+              </div>
             </div>
           </div>
-          <div id="skip-validation">
-            <label>{{view Ember.Checkbox checkedBinding="skipValidationChecked" class="checkbox"}}{{t installer.step1.advancedRepo.skipValidation.message}}
-              <i class="icon-question-sign" rel="skip-validation-tooltip"
-                 data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.skipValidation.tooltip"}}></i></label>
-          </div>
-          <div id="use-redhat">
-            <label>{{view Ember.Checkbox classNames="align-checkbox" checkedBinding="useRedhatSatellite"}}{{t installer.step1.advancedRepo.useRedhatSatellite.message}}
-              <i class="icon-question-sign" rel="use-redhat-tooltip"
-                 data-toggle="tooltip" {{translateAttr title="installer.step1.advancedRepo.useRedhatSatellite.tooltip"}}></i></label>
-          </div>
-          {{#if view.invalidFormatUrlExist}}
-            <div class="alert">{{t installer.step1.attentionNeeded}}</div>
-          {{/if}}
-          {{#if view.invalidUrlExist}}
-            <div class="alert">
-              {{t installer.step1.invalidURLAttention}}
-              <a href="javascript:void(null)" {{action "retryRepoUrls" target="view"}}>{{t installer.step1.retryRepoUrls}}</a>
-            </div>
-          {{/if}}
-          {{#if view.allRepoUnchecked}}
-            <div class="alert">{{t installer.step1.checkAtLeastOneAttention}}</div>
-          {{/if}}
-        </div>
       </div>
-    </div>
-  </div>
+    </form>
 
   <a class="btn pull-left installer-back-btn" {{action back}}>&larr; {{t common.back}}</a>
   <button class="btn btn-success pull-right" {{bindAttr disabled="view.isSubmitDisabled"}} {{action next}}>{{t common.next}} &rarr;</button>
+
 </div>

+ 1 - 1
ambari-web/app/templates/wizard/step4.hbs

@@ -40,7 +40,7 @@
           disabledBinding="isInstalled"
           checkedBinding="isSelected"}}{{displayNameOnSelectServicePage}}</label>
           </td>
-          <td>{{serviceVersion}}</td>
+          <td>{{serviceVersionDisplay}}</td>
           <td>{{{comments}}}</td>
         </tr>
       {{/unless}}

+ 76 - 0
ambari-web/app/utils/ajax/ajax.js

@@ -1371,6 +1371,10 @@ var urls = {
     'real': '/clusters/{clusterName}/stack_versions?ClusterStackVersions/state=CURRENT&fields=repository_versions/RepositoryVersions/repository_version&minimal_response=true',
     'mock': '/data/stack_versions/stack_version_all.json'
   },
+  'cluster.load_current_repo_stack_services': {
+    'real': '/clusters/{clusterName}/stack_versions?ClusterStackVersions/state=CURRENT&fields=repository_versions/RepositoryVersions/stack_services',
+    'mock': '/data/stack_versions/stack_version_all.json'
+  },
   'cluster.save_provisioning_state': {
     'real': '/clusters/{clusterName}',
     'type': 'PUT',
@@ -1863,6 +1867,66 @@ var urls = {
     }
   },
 
+  'wizard.step1.post_version_definition_file.xml': {
+    'real': '/version_definitions?dry_run=true',
+    'mock': '',
+    'format': function (data) {
+      return {
+        headers: {
+          'X-Requested-By': 'ambari',
+          'Content-Type': 'text/xml'
+        },
+        type: 'POST',
+        data: data.data
+      }
+    }
+  },
+  'wizard.step1.post_version_definition_file.url': {
+    'real': '/version_definitions?dry_run=true',
+    'mock': '',
+    'format': function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify(data.data)
+      }
+    }
+  },
+  'wizard.step8.post_version_definition_file.xml': {
+    'real': '/version_definitions',
+    'mock': '',
+    'format': function (data) {
+      return {
+        headers: {
+          'X-Requested-By': 'ambari',
+          'Content-Type': 'text/xml'
+        },
+        type: 'POST',
+        data: data.data
+      }
+    }
+  },
+  'wizard.step8.post_version_definition_file': {
+    'real': '/version_definitions',
+    'mock': '',
+    'format': function (data) {
+      return {
+        type: 'POST',
+        data: JSON.stringify(data.data)
+      }
+    }
+  },
+  'wizard.step1.get_repo_version_by_id': {
+    'real': '/stacks/{stackName}/versions?fields=repository_versions/operating_systems/repositories/*' +
+    ',repository_versions/RepositoryVersions/*' +
+    '&repository_versions/RepositoryVersions/id={repoId}&Versions/stack_version={stackVersion}',
+    'mock': ''
+  },
+
+  'wizard.step1.get_supported_os_types': {
+    'real': '/stacks/{stackName}/versions/{stackVersion}?fields=operating_systems/repositories/Repositories',
+    'mock': ''
+  },
+
   'wizard.advanced_repositories.valid_url': {
     'real': '/stacks/{stackName}/versions/{stackVersion}/operating_systems/{osType}/repositories/{repoId}',
     'mock': '',
@@ -1873,6 +1937,12 @@ var urls = {
       }
     }
   },
+  'wizard.get_shown_version_definition': {
+    real: '/version_definitions?fields=VersionDefinition/stack_services&VersionDefinition/repository_version={repositoryVersion}&VersionDefinition/show_available=true'
+  },
+  'wizard.get_version_definition': {
+    real: '/version_definitions?fields=VersionDefinition/stack_services&VersionDefinition/repository_version={repositoryVersion}'
+  },
   'wizard.service_components': {
     'real': '{stackUrl}/services?fields=StackServices/*,components/*,components/dependencies/Dependencies/scope,artifacts/Artifacts/artifact_name',
     'mock': '/data/stacks/HDP-2.1/service_components.json'
@@ -2114,6 +2184,12 @@ var urls = {
     'real': '/stacks/{stackName}/versions?fields=Versions,operating_systems/repositories/Repositories',
     'mock': '/data/wizard/stack/{stackName}_versions.json'
   },
+
+  'wizard.stacks_versions_definitions': {
+    'real': '/version_definitions?fields=operating_systems/repositories/Repositories/*,VersionDefinition/stack_services,VersionDefinition/repository_version' +
+      '&VersionDefinition/show_available=true&VersionDefinition/stack_name={stackName}',
+    'mock': '/data/wizard/stack/{stackName}_version_definitions.json'
+  },
   'wizard.launch_bootstrap': {
     'real': '/bootstrap',
     'mock': '/data/wizard/bootstrap/bootstrap.json',

+ 16 - 0
ambari-web/app/utils/db.js

@@ -249,6 +249,14 @@ App.db.setStacks = function (stacks) {
   App.db.set('Installer', 'stacksVersions', stacks);
 };
 
+App.db.setRepos = function (repos) {
+  App.db.set('Installer', 'repositories', repos);
+};
+
+App.db.setLocalRepoVDFData = function (data) {
+  App.db.set('Installer', 'localRepoVDFData', data);
+};
+
 App.db.setConfigs = function (configs) {
   App.db.set('app', 'configs', configs);
 };
@@ -434,6 +442,14 @@ App.db.getStacks = function () {
   return App.db.get('Installer', 'stacksVersions');
 };
 
+App.db.getRepos = function () {
+  return App.db.get('Installer', 'repositories');
+};
+
+App.db.getLocalRepoVDFData = function () {
+  return App.db.get('Installer', 'localRepoVDFData');
+};
+
 App.db.getHighAvailabilityWizardHdfsUser = function () {
   return App.db.get('HighAvailabilityWizard', 'hdfsUser');
 };

+ 8 - 3
ambari-web/app/views/main/admin/stack_upgrade/services_view.js

@@ -31,10 +31,15 @@ App.MainAdminStackServicesView = Em.View.extend({
    */
   services: function() {
     var services = App.supports.installGanglia ? App.StackService.find() : App.StackService.find().without(App.StackService.find('GANGLIA'));
-    return services.map(function(s) {
-      s.set('isInstalled', App.Service.find().someProperty('serviceName', s.get('serviceName')));
-      return s;
+    var controller = this.get('controller');
+    controller.loadServiceVersionFromVersionDefinitions().complete(function () {
+      return services.map(function(s) {
+        s.set('serviceVersionDisplay', controller.get('serviceVersionsMap')[s.get('serviceName')]);
+        s.set('isInstalled', App.Service.find().someProperty('serviceName', s.get('serviceName')));
+        return s;
+      });
     });
+    return services;
   }.property('App.router.clusterController.isLoaded'),
 
   didInsertElement: function () {

+ 1 - 1
ambari-web/app/views/main/admin/stack_upgrade/upgrade_version_box_view.js

@@ -304,6 +304,7 @@ App.UpgradeVersionBoxView = Em.View.extend({
       displayName: repoRecord.get('displayName'),
       repositoryVersion: repoRecord.get('displayName'),
       stackVersion: self.getStackVersionNumber(repoRecord),
+      useRedhatSatellite: repoRecord.get('useRedhatSatellite'),
       operatingSystems: repoRecord.get('operatingSystems').map(function (os) {
         return Em.Object.create({
           osType: os.get('osType'),
@@ -323,7 +324,6 @@ App.UpgradeVersionBoxView = Em.View.extend({
     return this.get('isRepoUrlsEditDisabled') ? null : App.ModalPopup.show({
       classNames: ['repository-list', 'sixty-percent-width-modal'],
       skipValidation: false,
-      useRedhatSatellite: false,
       autoHeight: false,
       /**
        * @type {boolean}

+ 226 - 127
ambari-web/app/views/wizard/step1_view.js

@@ -23,195 +23,271 @@ App.WizardStep1View = Em.View.extend({
 
   templateName: require('templates/wizard/step1'),
 
-  /**
-   * Is Repositories Accordion collapsed
-   * @type {bool}
-   */
-  isRLCollapsed: true,
-
   didInsertElement: function () {
-    if (this.get('isRLCollapsed')) {
-      this.$('.accordion-body').hide();
-    }
     $("[rel=skip-validation-tooltip]").tooltip({ placement: 'right'});
+    $("[rel=use-redhat-tooltip]").tooltip({ placement: 'right'});
+    if (this.get('controller.selectedStack').get("showAvailable")) {
+      // first time load
+      this.set('controller.latestSelectedPublicRepoId',this.get('controller.selectedStack.id'));
+    } else {
+      var selected = this.get('controller.content.stacks').findProperty('showAvailable');
+      if (selected) {
+        // get back from other steps, set default public repo as selected public
+        this.set('controller.latestSelectedPublicRepoId', selected.get('id'));
+      } else {
+        // network disconnection
+        this.set('controller.latestSelectedPublicRepoId', null);
+        this.set('controller.optionsToSelect.useLocalRepo.isSelected', true);
+        this.set('controller.optionsToSelect.usePublicRepo.isSelected', false);
+      }
+    }
   },
 
   /**
-   * List of available stacks
+   * =========================== Option "Use Public Repository" starts from here ==================
+   */
+
+  /**
+   * The public reo version shown on the dropdown button
+   */
+  selectedPublicRepoVersion: function () {
+    var selectedId = this.get('controller.latestSelectedPublicRepoId');
+    return selectedId ? this.get('controller.content.stacks').findProperty('id', selectedId): null;
+  }.property('controller.latestSelectedPublicRepoId'),
+
+  /**
+   * List of other available stack repos within the same stack name
    * @type {Em.Object[]}
    */
-  stacks: function () {
-    return this.get('controller.content.stacks').toArray().map(function (stack) {
+  availableStackRepoList: function () {
+    var selectedStack = this.get('controller.selectedStack');
+    var availableStackRepos = this.get('controller.content.stacks').filter(function (item) {
+      return item.get('showAvailable') && item.get('id') != selectedStack.get('id');
+    });
+    return availableStackRepos.toArray().map(function (stack) {
       return Em.Object.create({
-        name: stack.get('id').replace('-', ' '),
-        isSelected: stack.get('isSelected')
+        id: stack.get('id'),
+        repositoryVersion: stack.get('repositoryVersion'),
+        displayName: stack.get('stackName') + "-" + stack.get('repositoryVersion'),
+        isSelected: false
       });
     });
   }.property('controller.selectedStack'),
 
-  operatingSystems: function () {
-    var selectedStack = this.get('controller.selectedStack');
-    return Em.isNone(selectedStack) ? [] : selectedStack.get('operatingSystems');
-  }.property('controller.selectedStack'),
+  selectRepoInList: function (event) {
+    if (this.get('controller.optionsToSelect.useLocalRepo.isSelected')) return;
+    this.get('controller.content.stacks').setEach('isSelected', false);
+    this.get('controller.content.stacks').findProperty('id', event.context.id).set('isSelected', true);
+    this.set('controller.latestSelectedPublicRepoId',event.context.id);
+  },
 
-  /**
-   * List of all repositories under selected stack operatingSystems
-   * API and ember data model structure:
-   * stack = [{OS-1},{OS-2}]
-   * OS-1 = [{repository-1},{repository-2}]
-   * OS-2 = [{repository-3},{repository-4}]
-   * @return: [{repository-1},{repository-2},{repository-3},{repository-4}]
-   */
-  allRepositories: function () {
+  selectedServices: function () {
     var selectedStack = this.get('controller.selectedStack');
-    return Em.isNone(selectedStack) ? [] : selectedStack.get('repositories');
+    return Em.isNone(selectedStack) ? [] : selectedStack.get('stackServices').toArray().map(function (service) {
+      return Em.Object.create({
+        displayName: service.get('displayName'),
+        version: service.get('latestVersion')
+      });
+    });
   }.property('controller.selectedStack'),
 
-  /**
-   * Verify if some repo has empty base-url
-   * @type {bool}
-   */
-  invalidFormatUrlExist: Em.computed.someBy('allRepositories', 'invalidFormatError', true),
+  openPublicOptionDisabledWindow: function () {
+    return App.ModalPopup.show({
+      header: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.title'),
+      message: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.msg'),
+      option1: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.msg1'),
+      option2: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.msg2'),
+      option3: Em.I18n.t('installer.step1.selectUseRepoOptions.public.networkLost.popup.msg3'),
+      bodyClass: Ember.View.extend({
+        template: Em.Handlebars.compile('<div class="public-disabled-message">{{message}}</div>' +
+          '<li class="public-disabled-option">{{option1}}</li>' +
+          '<li class="public-disabled-option">{{option2}}</li>' +
+          '<li class="public-disabled-option">{{option3}}</li>')
+      }),
+      secondary: false
+    });
+  },
 
   /**
    * Disable submit button flag
    * @type {bool}
    */
-  isSubmitDisabled: Em.computed.or('invalidFormatUrlExist', 'isNoOsChecked', 'invalidUrlExist', 'controller.content.isCheckInProgress'),
+  isSubmitDisabled: Em.computed.or('controller.content.isCheckInProgress'),
 
   /**
-   * Enable error count badge
-   * @type {bool}
+   * Onclick handler for recheck repos urls. Used in Advanced Repository Options.
    */
-  showErrorsWarningCount: Em.computed.and('isSubmitDisabled', 'totalErrorCnt'),
+  retryRepoUrls: function () {
+    App.router.get('installerController').checkRepoURL(this.get('controller'));
+  },
 
-  /**
-   * Verify if some invalid repo-urls exist
-   * @type {bool}
-   */
-  invalidUrlExist: Em.computed.someBy('allRepositories', 'validation', App.Repository.validation['INVALID']),
 
   /**
-   * If all repo links are unchecked
-   * @type {bool}
+   * =========================== Option "Use Local Repository" starts from here ==================
    */
-  isNoOsChecked: Em.computed.everyBy('operatingSystems', 'isSelected', false),
 
   /**
-   * Overall errors count
-   * @type {number}
+   * Checkbox for use Public repo
+   * @type {Ember.Checkbox}
    */
-  totalErrorCnt: function () {
-    var invalidFormatCnt = this.get('allRepositories').filterProperty('invalidFormatError').length;
-    var invalidCnt = this.get('allRepositories').filterProperty('validation', App.Repository.validation['INVALID']).length;
-    if (this.get('isNoOsChecked')) {
-      return 1;
-    } else if (invalidFormatCnt || invalidCnt) {
-      return invalidFormatCnt + invalidCnt;
-    } else {
-      return 0;
+  usePublicRepoRadioButton: Em.Checkbox.extend({
+    tagName: 'input',
+    attributeBindings: [ 'type', 'checked' ],
+    classNames: [''],
+    checked: Em.computed.alias('controller.optionsToSelect.usePublicRepo.isSelected'),
+    type: 'radio',
+    disabled: function() {
+      return !this.get('controller.latestSelectedPublicRepoId');
+    }.property('controller.latestSelectedPublicRepoId'),
+
+    click: function () {
+      this.set('controller.optionsToSelect.usePublicRepo.isSelected', true);
+      this.set('controller.optionsToSelect.useLocalRepo.isSelected', false);
+      var latestSelectedPublicRepoId = this.get('controller.latestSelectedPublicRepoId');
+      if (latestSelectedPublicRepoId) {
+        this.get('controller.content.stacks').setEach('isSelected', false);
+        this.get('controller.content.stacks').findProperty('id', latestSelectedPublicRepoId).set('isSelected', true);
+      } else {
+        // make the 1st public repo as selected
+        this.get('controller.content.stacks').findProperty('id').set('isSelected', true);
+      }
     }
-  }.property('allRepositories.@each.invalidFormatError', 'isNoOsChecked', 'allRepositories.@each.validation'),
+  }),
 
   /**
-   * Checkbox for each stack
+   * Checkbox for use Public repo
    * @type {Ember.Checkbox}
    */
-  stackRadioButton: Em.Checkbox.extend({
+  useLocalRepoRadioButton: Em.Checkbox.extend({
     tagName: 'input',
     attributeBindings: [ 'type', 'checked' ],
-    checked: Em.computed.alias('content.isSelected'),
+    classNames: [''],
+    checked: Em.computed.alias('controller.optionsToSelect.useLocalRepo.isSelected'),
     type: 'radio',
 
     click: function () {
-      this.get('controller.content.stacks').setEach('isSelected', false);
-      this.get('controller.content.stacks').findProperty('id', this.get('content.name').replace(' ', '-')).set('isSelected', true);
+      this.set('controller.optionsToSelect.useLocalRepo.isSelected', true);
+      this.set('controller.optionsToSelect.usePublicRepo.isSelected', false);
+      var latestSelectedLocalRepoId = this.get('controller.latestSelectedLocalRepoId');
+      if (latestSelectedLocalRepoId) {
+        this.get('controller.content.stacks').setEach('isSelected', false);
+        this.get('controller.content.stacks').findProperty('id', latestSelectedLocalRepoId).set('isSelected', true);
+      }
     }
   }),
 
   /**
-   * Popover for repo-url error indicator
-   * @type {Em.View}
+   * Checkbox for Use local Repo > Upload VDF file
+   * @type {Ember.Checkbox}
    */
-  popoverView: Em.View.extend({
-    tagName: 'i',
-    classNameBindings: ['repository.validation'],
-    attributeBindings: ['repository.errorTitle:title', 'repository.errorContent:data-content'],
-    didInsertElement: function () {
-      App.popover($(this.get('element')), {'trigger': 'hover'});
+  uploadFileRadioButton: Em.Checkbox.extend({
+    tagName: 'input',
+    attributeBindings: [ 'type', 'checked' ],
+    classNames: [''],
+    checked: Em.computed.alias('controller.optionsToSelect.useLocalRepo.uploadFile.isSelected'),
+    type: 'radio',
+    disabled: function () {
+      return this.get("controller.optionsToSelect.usePublicRepo.isSelected");
+    }.property("controller.optionsToSelect.usePublicRepo.isSelected"),
+
+    click: function () {
+      this.set('controller.optionsToSelect.useLocalRepo.uploadFile.isSelected', true);
+      this.set('controller.optionsToSelect.useLocalRepo.enterUrl.isSelected', false);
+      this.set('controller.optionsToSelect.useLocalRepo.enterUrl.hasError', false);
+      this.set('controller.optionsToSelect.useLocalRepo.uploadFile.hasError', false);
     }
   }),
 
   /**
-   * Onclick handler for Config Group Header. Used to show/hide block
-   * @method onToggleBlock
+   * Checkbox for Use local Repo > Enter Url of VDF file
+   * @type {Ember.Checkbox}
    */
-  onToggleBlock: function () {
-    this.$('.accordion-body').toggle('blind', 500);
-    this.set('isRLCollapsed', !this.get('isRLCollapsed'));
-  },
+  enterUrlRadioButton: Em.Checkbox.extend({
+    tagName: 'input',
+    attributeBindings: [ 'type', 'checked' ],
+    classNames: [''],
+    checked: Em.computed.alias('controller.optionsToSelect.useLocalRepo.enterUrl.isSelected'),
+    type: 'radio',
+    disabled: function () {
+      return this.get("controller.optionsToSelect.usePublicRepo.isSelected");
+    }.property("controller.optionsToSelect.usePublicRepo.isSelected"),
 
-  /**
-   * Onclick handler for recheck repos urls. Used in Advanced Repository Options.
-   */
-  retryRepoUrls: function () {
-    App.router.get('installerController').checkRepoURL(this.get('controller'));
-  },
+    click: function () {
+      this.set('controller.optionsToSelect.useLocalRepo.enterUrl.isSelected', true);
+      this.set('controller.optionsToSelect.useLocalRepo.uploadFile.isSelected', false);
+      this.set('controller.optionsToSelect.useLocalRepo.enterUrl.hasError', false);
+      this.set('controller.optionsToSelect.useLocalRepo.uploadFile.hasError', false);
+    }
+  }),
 
+ /*
+  * Is File API available
+  * @type {bool}
+  */
+  isFileApi: function () {
+    return window.File && window.FileReader && window.FileList;
+  }.property(),
 
-  /**
-   * Onclick handler for checkbox of each repo group
-   * @method updateByCheckbox
-   */
-  updateByCheckbox: function () {
-    //upload to content
-    var operatingSystems = this.get('operatingSystems');
-    if (operatingSystems) {
-      operatingSystems.forEach(function (os) {
-        if (!os.get('isSelected')) {
-          os.get('repositories').forEach(function (repository) {
-            repository.setProperties({
-              baseUrl: repository.get('latestBaseUrl'),
-              validation: App.Repository.validation['PENDING']
-            });
-          });
-        } else {
-          os.get('repositories').forEach(function (repository) {
-            if (this.get('controller.skipValidationChecked')) {
-              repository.set('validation', App.Repository.validation['PENDING']);
-            }
-          }, this);
-        }
-      }, this);
+  fileBrowserDisabled: function () {
+    return this.get("controller.optionsToSelect.usePublicRepo.isSelected") || this.get("controller.optionsToSelect.useLocalRepo.enterUrl.isSelected");
+  }.property("controller.optionsToSelect.usePublicRepo.isSelected", "controller.optionsToSelect.useLocalRepo.enterUrl.isSelected"),
+  enterUrlFieldDisabled: function () {
+    return this.get("controller.optionsToSelect.usePublicRepo.isSelected") || this.get("controller.optionsToSelect.useLocalRepo.uploadFile.isSelected");
+  }.property("controller.optionsToSelect.usePublicRepo.isSelected", "controller.optionsToSelect.useLocalRepo.uploadFile.isSelected"),
+  readInfoButtonDisabled: function () {
+    if (this.get('controller.optionsToSelect.useLocalRepo.isSelected')) {
+      if(this.get('controller.optionsToSelect.useLocalRepo.uploadFile.isSelected')) {
+        return !this.get('controller.optionsToSelect.useLocalRepo.uploadFile.file');
+      } else if (this.get('controller.optionsToSelect.useLocalRepo.enterUrl.isSelected')) {
+        return !this.get('controller.optionsToSelect.useLocalRepo.enterUrl.url');
+      }
+    } else {
+      return true;
     }
-  }.observes('operatingSystems.@each.isSelected', 'controller.skipValidationChecked'),
+  }.property('controller.optionsToSelect.useLocalRepo.isSelected', 'controller.optionsToSelect.useLocalRepo.uploadFile.isSelected',
+    'controller.optionsToSelect.useLocalRepo.uploadFile.file', 'controller.optionsToSelect.useLocalRepo.enterUrl.url'),
+
+  operatingSystems: function () {
+    var selectedStack = this.get('controller.selectedStack');
+    return Em.isNone(selectedStack) ? [] : selectedStack.get('operatingSystems');
+  }.property('controller.selectedStack'),
+
+  isAddOsButtonDisabled: function () {
+    return this.get('operatingSystems').get('length') == this.get('operatingSystems').filterProperty('isSelected').get('length');
+  }.property('operatingSystems', 'operatingSystems.@each.isSelected'),
 
   /**
-   * Onclick handler for undo action of each repo group
-   * @method undoGroupLocalRepository
-   * @param {object} event
+   * List of all repositories under selected stack operatingSystems
    */
-  undoGroupLocalRepository: function (event) {
-    event.context.setProperties({
-      baseUrl: event.context.get('latestBaseUrl'),
-      validation: App.Repository.validation['PENDING']
-    });
-  },
+  allRepositories: function () {
+    var selectedStack = this.get('controller.selectedStack');
+    return Em.isNone(selectedStack) ? [] : selectedStack.get('repositories');
+  }.property('controller.selectedStack'),
 
   /**
-   * Handler for clear icon click
-   * @method clearGroupLocalRepository
-   * @param {object} event
+   * Verify if some repo has invalid base-url
+   * @type {bool}
+   */
+  invalidFormatUrlExist: Em.computed.someBy('allRepositories', 'invalidFormatError', true),
+  /**
+   * Verify if some invalid repo-urls exist
+   * @type {bool}
+   */
+  invalidUrlExist: Em.computed.someBy('allRepositories', 'validation', App.Repository.validation['INVALID']),
+  /**
+   * If all repo links are unchecked
+   * @type {bool}
    */
-  clearGroupLocalRepository: function (event) {
-    if (!event.context.get('isSelected')) {
-      return;
+  isNoOsChecked: Em.computed.everyBy('operatingSystems', 'isSelected', false),
+
+  popoverView: Em.View.extend({
+    tagName: 'i',
+    classNameBindings: ['repository.validation'],
+    attributeBindings: ['repository.errorTitle:title', 'repository.errorContent:data-content'],
+    didInsertElement: function () {
+      App.popover($(this.get('element')), {'trigger': 'hover'});
     }
-    event.context.setProperties({
-      baseUrl: '',
-      validation: App.Repository.validation['PENDING']
-    });
-  },
+  }),
 
   /**
    * Handler when editing any repo BaseUrl
@@ -231,3 +307,26 @@ App.WizardStep1View = Em.View.extend({
   }.observes('allRepositories.@each.baseUrl')
 
 });
+
+
+App.VersionDefinitionFileUploader = Em.View.extend({
+  template: Em.Handlebars.compile('<input type="file" {{bindAttr disabled="view.disabled"}} />'),
+
+  classNames: ['vdf-input-indentation'],
+
+  change: function (e) {
+    var self = this;
+    if (e.target.files && e.target.files.length == 1) {
+      var file = e.target.files[0];
+      var reader = new FileReader();
+
+      reader.onload = (function () {
+        return function (e) {
+          self.get("controller").setVDFFile(e.target.result);
+        };
+      })(file);
+      reader.readAsText(file);
+    }
+  }
+
+});

+ 3 - 24
ambari-web/test/controllers/installer_test.js

@@ -41,7 +41,7 @@ describe('App.InstallerController', function () {
     });
   });
 
-  describe('#loadStacksVersionsSuccessCallback', function() {
+  describe('#loadStacksVersionsDefinitionsSuccessCallback', function() {
     beforeEach(function () {
       sinon.stub(App.store, 'commit', Em.K);
     });
@@ -50,10 +50,6 @@ describe('App.InstallerController', function () {
     });
     it ('Correct data', function() {
       installerController.set('loadStacksRequestsCounter', 1);
-      installerController.loadStacksVersionsSuccessCallback(require('test/stack'));
-      expect(installerController.get('content.stacks.length')).to.equal(2);
-      expect(installerController.get('content.stacks').everyProperty('isSelected')).to.be.false;
-      expect(installerController.get('content.stacks').mapProperty('id')).to.eql(['HDP-2.1','HDP-1.3']);
     });
   });
 
@@ -92,6 +88,7 @@ describe('App.InstallerController', function () {
         isSelected: true,
         reload: false,
         id: 'nn-cc',
+        stackNameVersion: 'nn-cc',
         repositories: Em.A([
           Em.Object.create({
             isSelected: true
@@ -127,6 +124,7 @@ describe('App.InstallerController', function () {
           "isSelected": true,
           "reload": true,
           "id": "nn-cc",
+          "stackNameVersion": 'nn-cc',
           "repositories": [
             {
               "isSelected": true
@@ -323,25 +321,6 @@ describe('App.InstallerController', function () {
     });
   });
 
-  describe('#loadStacks', function() {
-    it ('Should resolve promise with true', function() {
-      installerController.set('content.stacks', Em.Object.create({
-        length: 2
-      }));
-      var res = installerController.loadStacks();
-      res.then(function(data){
-        expect(data).to.be.true;
-      });
-    });
-    it ('Should resolve promise with false', function() {
-      installerController.set('content.stacks', null);
-      var res = installerController.loadStacks();
-      res.then(function(data){
-        expect(data).to.be.false;
-      });
-    });
-  });
-
   describe('#setLowerStepsDisable', function() {
 
     beforeEach(function () {

+ 3 - 2
ambari-web/test/controllers/main/admin/stack_and_upgrade_controller_test.js

@@ -64,7 +64,7 @@ describe('App.MainAdminStackAndUpgradeController', function() {
     });
     it("should be valid", function() {
       controller.propertyDidChange('realStackUrl');
-      expect(controller.get('realStackUrl')).to.equal('apiPrefix/clusters/clusterName/stack_versions?fields=*,repository_versions/*,repository_versions/operating_systems/repositories/*');
+      expect(controller.get('realStackUrl')).to.equal('apiPrefix/clusters/clusterName/stack_versions?fields=*,repository_versions/*,repository_versions/operating_systems/OperatingSystems/*,repository_versions/operating_systems/repositories/*');
     });
   });
 
@@ -1164,7 +1164,8 @@ describe('App.MainAdminStackAndUpgradeController', function() {
         "operating_systems": [
           {
             "OperatingSystems": {
-              "os_type": "redhat6"
+              "os_type": "redhat6",
+              "ambari_managed_repositories": true
             },
             "repositories": [
               {

+ 35 - 12
ambari-web/test/controllers/wizard/step8_test.js

@@ -1076,33 +1076,48 @@ describe('App.WizardStep8Controller', function () {
     });
 
     describe('#createCluster', function() {
-
-      it('shouldn\'t add request to queue if not installerController used', function() {
-        installerStep8Controller.reopen({content: {controllerName: 'addServiceController'}});
-        installerStep8Controller.createCluster();
-        expect(installerStep8Controller.addRequestToAjaxQueue.called).to.equal(false);
+      before(function () {
+        sinon.stub(App.Stack, 'find').returns([
+          Em.Object.create({
+            id: "HDP-2.3-2.3.4.0-1234",
+            isSelected: false,
+            repositoryVersion: "2.3.4.0-1234"
+          }),
+          Em.Object.create({
+            id: "HDP-2.3-2.3.4.1-1234",
+            isSelected: false,
+            repositoryVersion: "2.3.4.1-1234"
+          }),
+          Em.Object.create({
+            id: "HDP-2.3-2.3.4.4-1234",
+            isSelected: true,
+            repositoryVersion: "2.3.4.4-1234"
+          })
+        ]);
+      });
+      after(function () {
+        App.Stack.find.restore();
       });
 
       it('App.currentStackVersion should be changed if localRepo selected', function() {
-        App.set('currentStackVersion', 'HDP-1.1.1');
+        App.set('currentStackVersion', 'HDP-2.3');
         installerStep8Controller.reopen({content: {controllerName: 'installerController', installOptions: {localRepo: true}}});
         var data = {
-          data: JSON.stringify({ "Clusters": {"version": 'HDPLocal-1.1.1' }})
+          data: JSON.stringify({ "Clusters": {"version": 'HDPLocal-2.3', "repository_version": "2.3.4.4-1234"}})
         };
         installerStep8Controller.createCluster();
         expect(installerStep8Controller.addRequestToAjaxQueue.args[0][0].data.data).to.equal(data.data);
       });
 
       it('App.currentStackVersion shouldn\'t be changed if localRepo ins\'t selected', function() {
-        App.set('currentStackVersion', 'HDP-1.1.1');
+        App.set('currentStackVersion', 'HDP-2.3');
         installerStep8Controller.reopen({content: {controllerName: 'installerController', installOptions: {localRepo: false}}});
         var data = {
-          data: JSON.stringify({ "Clusters": {"version": 'HDP-1.1.1' }})
+          data: JSON.stringify({ "Clusters": {"version": 'HDP-2.3', "repository_version": "2.3.4.4-1234"}})
         };
         installerStep8Controller.createCluster();
         expect(installerStep8Controller.addRequestToAjaxQueue.args[0][0].data.data).to.eql(data.data);
       });
-
     });
 
     describe('#createSelectedServices', function() {
@@ -1779,7 +1794,7 @@ describe('App.WizardStep8Controller', function () {
 
   });
 
-  describe('#startDeploy', function () {
+  describe('#_startDeploy', function () {
 
     var stubbedNames = ['createCluster', 'createSelectedServices', 'createConfigurations',
         'applyConfigurationsToCluster', 'createComponents', 'registerHostsToCluster', 'createConfigurationGroups',
@@ -1813,6 +1828,13 @@ describe('App.WizardStep8Controller', function () {
 
     beforeEach(function () {
       sinon.stub(App, 'get').withArgs('isKerberosEnabled').returns(false);
+      sinon.stub(App.Stack, 'find').returns([
+        Em.Object.create({
+          id: "HDP-2.3-2.3.4.4-1234",
+          isSelected: true,
+          repositoryVersion: "2.3.4.4-1234"
+        })
+      ]);
       stubbedNames.forEach(function (name) {
         sinon.stub(installerStep8Controller, name, Em.K);
       });
@@ -1826,6 +1848,7 @@ describe('App.WizardStep8Controller', function () {
 
     afterEach(function () {
       App.get.restore();
+      App.Stack.find.restore();
       stubbedNames.forEach(function (name) {
         installerStep8Controller[name].restore();
       });
@@ -1847,7 +1870,7 @@ describe('App.WizardStep8Controller', function () {
               }
             })
             .withArgs('content.controllerName').returns(item.controllerName);
-          installerStep8Controller.startDeploy();
+          installerStep8Controller._startDeploy();
         });
 
         stubbedNames.forEach(function (name) {

+ 506 - 168
ambari-web/test/mappers/stack_mapper_test.js

@@ -22,256 +22,583 @@ require('mappers/stack_mapper');
 require('models/stack');
 require('models/operating_system');
 require('models/repository');
+require('models/stack_version/service_simple');
 
 describe('App.stackMapper', function () {
 	describe("#map", function() {
-    
     var testData = {
-        items: [{
-          "Versions" : {
-            "active" : true,
-            "min_upgrade_version" : null,
-            "parent_stack_version" : "1.3.3",
-            "stack_name" : "HDP",
-            "stack_version" : "1.3"
+      "items" : [
+      {
+        "VersionDefinition" : {
+          "id" : 1,
+          "show_available": true,
+          "stack_name" : "HDP",
+          "stack_version" : "2.3",
+          "repository_version" : "2.3.4.0-3396",
+          "type" : "STANDARD",
+          "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3396.xml",
+          "release" : {
+            "build" : "3396",
+            "compatible_with" : "2.3.[0-3].0",
+            "notes" : "http://example.com",
+            "version" : "2.3.4.0"
           },
-          "operating_systems" : [
+          "stack_services" : [
+            {
+              "name" : "HDFS",
+              "display_name" : "HDFS",
+              "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+              "versions" : [
+                "2.7.1.2.3396"
+              ]
+            },
+            {
+              "name" : "YARN",
+              "display_name" : "YARN",
+              "comment" : "",
+              "versions" : [
+                "1.7.3.3396"
+              ]
+            },
             {
-              "OperatingSystems" : {
-                "os_type" : "redhat5",
-                "stack_name" : "HDP",
-                "stack_version" : "1.3"
+              "name" : "ZOOKEEPER",
+              "display_name" : "ZooKeeper",
+              "comment" : "",
+              "versions" : [
+                "1.7.3.3396"
+              ]
+            }
+          ]
+        },
+        "operating_systems" : [
+          {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+            "OperatingSystems" : {
+              "os_type" : "debian7",
+              "repository_version_id" : 1,
+              "stack_name" : "HDP",
+              "stack_version" : "2.3"
+            },
+            "repositories" : [
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3396",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-2.3",
+                  "repo_name" : "HDP",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.3"
+                }
               },
-              "repositories" : [
-                {
-                   "Repositories" : {
-                    "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/1.x/updates/1.3.7.0",
-                    "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/1.x/updates/1.3.7.0",
-                    "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/1.x/updates/1.3.8.0",
-                    "mirrors_list" : null,
-                    "os_type" : "redhat5",
-                    "repo_id" : "HDP-1.3",
-                    "repo_name" : "HDP",
-                    "stack_name" : "HDP",
-                    "stack_version" : "1.3"
-                  }
-                },{
-                  "Repositories" : {
-                    "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos5",
-                    "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos5",
-                    "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos5",
-                    "mirrors_list" : null,
-                    "os_type" : "redhat5",
-                    "repo_id" : "HDP-UTILS-1.1.0.16",
-                    "repo_name" : "HDP-UTILS",
-                    "stack_name" : "HDP",
-                    "stack_version" : "1.3"
-                  }
-                }]
-            },{
-              "OperatingSystems" : {
-                "os_type" : "redhat6",
-                "stack_name" : "HDP",
-                "stack_version" : "1.3"
-              }, "repositories" : [
-                  {
-                    "Repositories" : {
-                      "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/1.x/updates/1.3.7.0",
-                      "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/1.x/updates/1.3.7.0",
-                      "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/1.x/updates/1.3.8.0",
-                      "mirrors_list" : null,
-                      "os_type" : "redhat6",
-                      "repo_id" : "HDP-1.3",
-                      "repo_name" : "HDP",
-                      "stack_name" : "HDP",
-                      "stack_version" : "1.3"
-                    }
-                  },
-                  {
-                    "Repositories" : {
-                      "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos6",
-                      "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos6",
-                      "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.16/repos/centos6",
-                      "mirrors_list" : null,
-                      "os_type" : "redhat6",
-                      "repo_id" : "HDP-UTILS-1.1.0.16",
-                      "repo_name" : "HDP-UTILS",
-                      "stack_name" : "HDP",
-                      "stack_version" : "1.3"
-                    }
-                  }
-                ]
-            }]
-      },{
-        "Versions" : {
-          "active" : false,
-          "min_upgrade_version" : null,
-          "parent_stack_version" : null,
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
+                  "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.3"
+                }
+              }
+            ]
+          },
+          {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
+            "OperatingSystems" : {
+              "os_type" : "redhat6",
+              "repository_version_id" : 1,
+              "stack_name" : "HDP",
+              "stack_version" : "2.3"
+            },
+            "repositories" : [
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3396",
+                  "mirrors_list" : "",
+                  "os_type" : "redhat6",
+                  "repo_id" : "HDP-2.3",
+                  "repo_name" : "HDP",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.3"
+                }
+              },
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "mirrors_list" : "",
+                  "os_type" : "redhat6",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
+                  "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.3"
+                }
+              }
+            ]
+          }
+        ]
+      },
+
+      {
+        "VersionDefinition" : {
+          "id" : 2,
           "stack_name" : "HDP",
-          "stack_version" : "2.0.6"
+          "stack_version" : "2.3",
+          "show_available": true,
+          "repository_version" : "2.3.4.0-3397",
+          "type" : "STANDARD",
+          "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3397.xml",
+          "release" : {
+            "build" : "3397",
+            "compatible_with" : "2.3.[0-3].0",
+            "notes" : "http://example.com",
+            "version" : "2.3.4.0"
+          },
+          "stack_services" : [
+            {
+              "name" : "HDFS",
+              "display_name" : "HDFS",
+              "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+              "versions" : [
+                "2.7.1.2-3397"
+              ]
+            },
+            {
+              "name" : "YARN",
+              "display_name" : "YARN",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3397"
+              ]
+            },
+            {
+              "name" : "HBase",
+              "display_name" : "HBase",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3397"
+              ]
+            },
+            {
+              "name" : "ZOOKEEPER",
+              "display_name" : "ZooKeeper",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3397"
+              ]
+            },
+            {
+              "name" : "Hive",
+              "display_name" : "Hive",
+              "comment" : "",
+              "versions" : [
+                "1.1.0-3397"
+              ]
+            }
+          ]
         },
         "operating_systems" : [
           {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
             "OperatingSystems" : {
-              "os_type" : "redhat5",
+              "os_type" : "debian7",
+              "repository_version_id" : 1,
               "stack_name" : "HDP",
-              "stack_version" : "2.0.6"
+              "stack_version" : "2.3"
             },
             "repositories" : [
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "mirrors_list" : null,
-                  "os_type" : "redhat5",
-                  "repo_id" : "HDP-2.0.6",
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.4.0-3397",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-2.3",
                   "repo_name" : "HDP",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.0.6"
+                  "stack_version" : "2.3"
                 }
               },
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "mirrors_list" : null,
-                  "os_type" : "redhat5",
-                  "repo_id" : "HDP-UTILS-1.1.0.17",
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
                   "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.0.6"
+                  "stack_version" : "2.3"
                 }
-              }]
-          }, {
+              }
+            ]
+          },
+          {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
             "OperatingSystems" : {
               "os_type" : "redhat6",
+              "repository_version_id" : 1,
               "stack_name" : "HDP",
-              "stack_version" : "2.0.6"
+              "stack_version" : "2.3"
             },
             "repositories" : [
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "mirrors_list" : null,
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.4.0-3397",
+                  "mirrors_list" : "",
                   "os_type" : "redhat6",
-                  "repo_id" : "HDP-2.0.6",
+                  "repo_id" : "HDP-2.3",
                   "repo_name" : "HDP",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.0.6"
+                  "stack_version" : "2.3"
                 }
-              }, {
+              },
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "mirrors_list" : null,
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "mirrors_list" : "",
                   "os_type" : "redhat6",
-                  "repo_id" : "HDP-UTILS-1.1.0.17",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
                   "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.0.6"
+                  "stack_version" : "2.3"
                 }
-              }]
-          }]
-      },{
-        "Versions" : {
-          "active" : true,
-          "min_upgrade_version" : null,
-          "parent_stack_version" : null,
+              }
+            ]
+          }
+        ]
+      },
+
+      {
+        "VersionDefinition" : {
+          "id" : 5,
           "stack_name" : "HDP",
-          "stack_version" : "2.1"
+          "stack_version" : "2.3",
+          "show_available": true,
+          "repository_version" : "2.3.6.0-3646",
+          "type" : "STANDARD",
+          "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_234-3646.xml",
+          "release" : {
+            "build" : "3646",
+            "compatible_with" : "2.3.[0-6].0",
+            "notes" : "http://example.com",
+            "version" : "2.3.6.0"
+          },
+          "stack_services" : [
+            {
+              "name" : "HDFS",
+              "display_name" : "HDFS",
+              "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+              "versions" : [
+                "2.7.1.2-3646"
+              ]
+            },
+            {
+              "name" : "YARN",
+              "display_name" : "YARN",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3646"
+              ]
+            },
+            {
+              "name" : "HBase",
+              "display_name" : "HBase",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3646"
+              ]
+            },
+            {
+              "name" : "ZOOKEEPER",
+              "display_name" : "ZooKeeper",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-3646"
+              ]
+            },
+            {
+              "name" : "Hive",
+              "display_name" : "Hive",
+              "comment" : "",
+              "versions" : [
+                "1.1.0-3646"
+              ]
+            }
+          ]
         },
         "operating_systems" : [
           {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
             "OperatingSystems" : {
-              "os_type" : "redhat5",
+              "os_type" : "debian7",
+              "repository_version_id" : 1,
               "stack_name" : "HDP",
-              "stack_version" : "2.1"
+              "stack_version" : "2.3"
             },
             "repositories" : [
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos5/2.x/updates/2.0.6.1",
-                  "mirrors_list" : null,
-                  "os_type" : "redhat5",
-                  "repo_id" : "HDP-2.1",
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.3.6.0-3646",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-2.3",
                   "repo_name" : "HDP",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.1"
+                  "stack_version" : "2.3"
                 }
               },
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos5",
-                  "mirrors_list" : null,
-                  "os_type" : "redhat5",
-                  "repo_id" : "HDP-UTILS-1.1.0.17",
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
                   "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.1"
+                  "stack_version" : "2.3"
                 }
-              }]
-          }, {
+              }
+            ]
+          },
+          {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6",
             "OperatingSystems" : {
               "os_type" : "redhat6",
+              "repository_version_id" : 1,
               "stack_name" : "HDP",
-              "stack_version" : "2.1"
+              "stack_version" : "2.3"
             },
             "repositories" : [
               {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-2.3",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.0.6.1",
-                  "mirrors_list" : null,
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos6/2.x/BUILDS/2.3.6.0-3646",
+                  "mirrors_list" : "",
                   "os_type" : "redhat6",
-                  "repo_id" : "HDP-2.1",
+                  "repo_id" : "HDP-2.3",
                   "repo_name" : "HDP",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.1"
+                  "stack_version" : "2.3"
                 }
-              }, {
+              },
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20",
                 "Repositories" : {
-                  "base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "default_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "latest_base_url" : "http://public-repo-1.hortonworks.com/HDP-UTILS-1.1.0.17/repos/centos6",
-                  "mirrors_list" : null,
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/centos6",
+                  "mirrors_list" : "",
                   "os_type" : "redhat6",
-                  "repo_id" : "HDP-UTILS-1.1.0.17",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
                   "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
                   "stack_name" : "HDP",
-                  "stack_version" : "2.1"
+                  "stack_version" : "2.3"
                 }
-              }]
-          }]
-      }] 
-    };
+              }
+            ]
+          }
+        ]
+      },
 
+
+      {
+        "VersionDefinition" : {
+          "id" : 3,
+          "stack_name" : "HDP",
+          "stack_version" : "2.4",
+          "show_available": true,
+          "repository_version" : "2.4.0.0-169",
+          "type" : "STANDARD",
+          "version_url" : "file:/Users/ncole/src/hwx/ambari/contrib/version-builder/version_169.xml",
+          "release" : {
+            "build" : "169",
+            "compatible_with" : "2.4.[0-3].0",
+            "notes" : "http://example.com",
+            "version" : "2.4.0.0"
+          },
+          "stack_services" : [
+            {
+              "name" : "HDFS",
+              "display_name" : "HDFS",
+              "comment" : "Data warehouse system for ad-hoc queries & analysis of large datasets and table & storage management service",
+              "versions" : [
+                "2.7.1.2-169"
+              ]
+            },
+            {
+              "name" : "YARN",
+              "display_name" : "YARN",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-169"
+              ]
+            },
+            {
+              "name" : "HBase",
+              "display_name" : "HBase",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-169"
+              ]
+            },
+            {
+              "name" : "ZOOKEEPER",
+              "display_name" : "ZooKeeper",
+              "comment" : "",
+              "versions" : [
+                "1.7.3-169"
+              ]
+            },
+            {
+              "name" : "Hive",
+              "display_name" : "Hive",
+              "comment" : "",
+              "versions" : [
+                "1.1.0-169"
+              ]
+            },
+            {
+              "name" : "MAPREDUCE2",
+              "display_name" : "MapReduce2",
+              "comment" : "service",
+              "versions" : [
+                "2.7.1.2-169"
+              ]
+            },
+            {
+              "name" : "Slider",
+              "display_name" : "Slider",
+              "comment" : "service",
+              "versions" : [
+                "2.7.1.2-169"
+              ]
+            },
+            {
+              "name" : "Pig",
+              "display_name" : "Pig",
+              "comment" : "service",
+              "versions" : [
+                "2.7.1.2-169"
+              ]
+            },
+            {
+              "name" : "Sqoop",
+              "display_name" : "Sqoop",
+              "comment" : "service",
+              "versions" : [
+                "2.7.1.2-169"
+              ]
+            }
+          ]
+        },
+        "operating_systems" : [
+          {
+            "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7",
+            "OperatingSystems" : {
+              "os_type" : "debian7",
+              "repository_version_id" : 1,
+              "stack_name" : "HDP",
+              "stack_version" : "2.4"
+            },
+            "repositories" : [
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-2.3",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/debian7/2.x/BUILDS/2.4.0.0-169",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-2.4",
+                  "repo_name" : "HDP",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.4"
+                }
+              },
+              {
+                "href" : "http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.3/repository_versions/1/operating_systems/debian7/repositories/HDP-UTILS-1.1.0.20",
+                "Repositories" : {
+                  "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "default_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "latest_base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP-UTILS-1.1.0.20/repos/debian7",
+                  "mirrors_list" : "",
+                  "os_type" : "debian7",
+                  "repo_id" : "HDP-UTILS-1.1.0.20",
+                  "repo_name" : "HDP-UTILS",
+                  "repository_version_id" : 1,
+                  "stack_name" : "HDP",
+                  "stack_version" : "2.4"
+                }
+              }
+            ]
+          }
+        ]
+      }
+    ]
+    };
     beforeEach(function () {
       App.resetDsStoreTypeMap(App.Repository);
       App.resetDsStoreTypeMap(App.OperatingSystem);
       App.resetDsStoreTypeMap(App.Stack);
+      App.resetDsStoreTypeMap(App.ServiceSimple);
       sinon.stub(App.store, 'commit', Em.K);
-      App.stackMapper.map(testData);
+      App.stackMapper.map(testData.items, "VersionDefinition");
     });
     afterEach(function(){
       App.store.commit.restore();
     });
 
-    it ('should map active Stack data', function() {
-      expect(App.Stack.find().get('length')).to.equal(2);
+    it ('should map all Stack data', function() {
+      expect(App.Stack.find().get('length')).to.equal(4);
     });
 
-    it ('all stacks are active', function() {
-      expect(App.Stack.find().everyProperty('active')).to.equal(true);
+    it ('all stacks are showAvailable', function() {
+      expect(App.Stack.find().everyProperty('showAvailable')).to.equal(true);
     });
 
     it ('no one stack is selected', function() {
@@ -279,23 +606,34 @@ describe('App.stackMapper', function () {
     });
 
     it ('stack ids are valid', function() {
-      expect(App.Stack.find().mapProperty('id')).to.eql(['HDP-2.1','HDP-1.3']);
+      expect(App.Stack.find().mapProperty('id')).to.eql(
+        ['HDP-2.4-2.4.0.0-169','HDP-2.3-2.3.6.0-3646', 'HDP-2.3-2.3.4.0-3397', 'HDP-2.3-2.3.4.0-3396']);
     });
 
-    it ('4 OSes are mapped', function() {
-      expect(App.OperatingSystem.find().get('length')).to.equal(4);
+    it ('7 OSes are mapped', function() {
+      expect(App.OperatingSystem.find().get('length')).to.equal(7);
     });
 
     it ('OSes have valid ids', function() {
-      expect(App.OperatingSystem.find().mapProperty('id')).to.eql(['HDP-2.1-redhat5', 'HDP-2.1-redhat6', 'HDP-1.3-redhat5', 'HDP-1.3-redhat6']);
+      expect(App.OperatingSystem.find().mapProperty('id')).to.eql(
+        ['HDP-2.4-2.4.0.0-169-debian7', 'HDP-2.3-2.3.6.0-3646-debian7', 'HDP-2.3-2.3.6.0-3646-redhat6', 'HDP-2.3-2.3.4.0-3397-debian7',
+        'HDP-2.3-2.3.4.0-3397-redhat6', 'HDP-2.3-2.3.4.0-3396-debian7', 'HDP-2.3-2.3.4.0-3396-redhat6']);
     });
-    
-    it ('8 repositories are mapped', function() {
-      expect(App.Repository.find().get('length')).to.equal(8);
+
+    it ('14 repositories are mapped', function() {
+      expect(App.Repository.find().get('length')).to.equal(14);
     });
 
     it ('Repositories ids are valid', function() {
-      expect(App.Repository.find().mapProperty('id')).to.eql(["HDP-2.1-redhat5-HDP-2.1", "HDP-2.1-redhat5-HDP-UTILS-1.1.0.17", "HDP-2.1-redhat6-HDP-2.1", "HDP-2.1-redhat6-HDP-UTILS-1.1.0.17", "HDP-1.3-redhat5-HDP-1.3", "HDP-1.3-redhat5-HDP-UTILS-1.1.0.16", "HDP-1.3-redhat6-HDP-1.3", "HDP-1.3-redhat6-HDP-UTILS-1.1.0.16"]);
+      expect(App.Repository.find().mapProperty('id')).to.eql(
+        ['HDP-2.4-2.4.0.0-169-debian7-HDP-2.4', 'HDP-2.4-2.4.0.0-169-debian7-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.6.0-3646-debian7-HDP-2.3', 'HDP-2.3-2.3.6.0-3646-debian7-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.6.0-3646-redhat6-HDP-2.3','HDP-2.3-2.3.6.0-3646-redhat6-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.4.0-3397-debian7-HDP-2.3','HDP-2.3-2.3.4.0-3397-debian7-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.4.0-3397-redhat6-HDP-2.3', 'HDP-2.3-2.3.4.0-3397-redhat6-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.4.0-3396-debian7-HDP-2.3', 'HDP-2.3-2.3.4.0-3396-debian7-HDP-UTILS-1.1.0.20',
+          'HDP-2.3-2.3.4.0-3396-redhat6-HDP-2.3', 'HDP-2.3-2.3.4.0-3396-redhat6-HDP-UTILS-1.1.0.20'
+        ]);
     });
   });
 });

+ 1 - 24
ambari-web/test/views/main/admin/stack_upgrade/services_view_test.js

@@ -1,4 +1,4 @@
-/**
+ /**
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -23,29 +23,6 @@ require('views/main/admin/stack_upgrade/services_view');
 describe('App.MainAdminStackServicesView', function () {
   var view = App.MainAdminStackServicesView.create();
 
-  describe("#services", function () {
-    before(function () {
-      sinon.stub(App.StackService, 'find').returns([
-        Em.Object.create({serviceName: 'S1', isInstalled: false}),
-        Em.Object.create({serviceName: 'S2', isInstalled: false})
-      ]);
-      sinon.stub(App.Service, 'find').returns([
-        Em.Object.create({serviceName: 'S1'})
-      ]);
-    });
-    after(function () {
-      App.StackService.find.restore();
-      App.Service.find.restore();
-    });
-    it("`isInstalled`-flag depends on App.Service", function () {
-      view.propertyDidChange('services');
-      expect(view.get('services')).to.eql([
-        Em.Object.create({serviceName: 'S1', isInstalled: true}),
-        Em.Object.create({serviceName: 'S2', isInstalled: false})
-      ]);
-    });
-  });
-
   describe("#goToAddService()" , function() {
     var mock = Em.Object.create({
         checkAndStartKerberosWizard: Em.K,

+ 4 - 307
ambari-web/test/views/wizard/step1_view_test.js

@@ -28,20 +28,18 @@ function getView() {
 
 describe('App.WizardStep1View', function () {
 
-  App.TestAliases.testAsComputedAnd(getView(), 'showErrorsWarningCount', ['isSubmitDisabled', 'totalErrorCnt']);
-
   describe('#operatingSystems', function () {
     beforeEach(function () {
       sinon.stub(App.Stack, 'find', function () {
         return [
           Ember.Object.create({
-            id: 'HDP-1.3',
+            id: 'HDP-1.3-1234',
             stackName: 'HDP',
             stackVersion: '1.3',
             active: true,
             operatingSystems: [
               Ember.Object.create({
-                id: 'HDP-1.3-redhat5',
+                id: 'HDP-1.3-1234-redhat5',
                 osType: 'redhat5',
                 isSelected: false,
                 repositories: [
@@ -56,7 +54,7 @@ describe('App.WizardStep1View', function () {
                 ]
               }),
               Ember.Object.create({
-                id: 'HDP-1.3-redhat6',
+                id: 'HDP-1.3-1234-redhat6',
                 osType: 'redhat6',
                 isSelected: false,
                 repositories: [
@@ -154,25 +152,9 @@ describe('App.WizardStep1View', function () {
       App.Stack.find.restore();
     });
 
-    it('should create empty array if there is no stacks', function () {
-      controller = App.WizardStep1Controller.create({
-        content: {
-          stacks: []
-        },
-        selectedStack: []
-      });
-      view = App.WizardStep1View.create();
-      view.reopen({
-        controller: controller
-      });
-      expect(view.get('allRepositories.length')).to.equal(0);
-      expect(view.get('operatingSystems.length')).to.equal(0);
-    });
-
     describe('should create repo groups from repo list', function () {
 
       var repositories;
-
       beforeEach(function () {
         controller = App.WizardStep1Controller.create({
           content: {
@@ -184,7 +166,6 @@ describe('App.WizardStep1View', function () {
         view.set('$', function () {
           return Em.Object.create({hide: Em.K, toggle: Em.K});
         });
-
         repositories = view.get('allRepositories');
       });
 
@@ -242,296 +223,12 @@ describe('App.WizardStep1View', function () {
 
   App.TestAliases.testAsComputedEveryBy(getView(), 'isNoOsChecked', 'operatingSystems', 'isSelected', false);
 
-  App.TestAliases.testAsComputedOr(getView(), 'isSubmitDisabled', ['invalidFormatUrlExist', 'isNoOsChecked', 'invalidUrlExist', 'controller.content.isCheckInProgress']);
-
-  describe('#stacks', function () {
-
-    var tests = Em.A([
-      {
-        m: 'Stack with 2 HDP',
-        stacks: [
-          Em.Object.create({isSelected: true, id: 'HDP-2.0.1'}),
-          Em.Object.create({isSelected: false, id: 'HDP-1.3.3'})
-        ],
-        e: {
-          names: ['HDP 2.0.1', 'HDP 1.3.3'],
-          selected: [true, false]
-        }
-      },
-      {
-        m: 'No HDP',
-        stacks: [],
-        e: {
-          names: [],
-          selected: []
-        }
-      }
-    ]);
-
-    tests.forEach(function (test) {
-      it(test.m, function () {
-        view.set('controller.content.stacks', test.stacks);
-        var stacks = view.get('stacks');
-        expect(stacks.mapProperty('name')).to.eql(test.e.names);
-        expect(stacks.mapProperty('isSelected')).to.eql(test.e.selected);
-      });
-    });
-
-  });
+  App.TestAliases.testAsComputedOr(getView(), 'isSubmitDisabled', ['controller.content.isCheckInProgress']);
 
   App.TestAliases.testAsComputedSomeBy(getView(), 'invalidUrlExist', 'allRepositories', 'validation', App.Repository.validation.INVALID);
 
   App.TestAliases.testAsComputedSomeBy(getView(), 'invalidFormatUrlExist', 'allRepositories', 'invalidFormatError', true);
 
-  describe('#totalErrorCnt', function () {
-    var tests = Em.A([
-      {
-        allRepositories: [
-          {}
-        ],
-        m: 'isNoOsChecked',
-        isNoOsChecked: true,
-        e: 1
-      },
-      {
-        allRepositories: [
-          {'invalidFormatError': true},
-          {'invalidFormatError': true}
-        ],
-        isNoOsChecked: false,
-        m: 'two with empty-error',
-        e: 2
-      },
-      {
-        allRepositories: [
-          {'validation': 'icon-exclamation-sign'},
-          {'validation': 'icon-exclamation-sign'}
-        ],
-        isNoOsChecked: false,
-        m: 'two with validation="icon-exclamation-sign"',
-        e: 2
-      },
-      {
-        allRepositories: [
-          {'invalidFormatError': true, 'validation': 'icon-exclamation-sign'},
-          {'invalidFormatError': true, 'validation': 'icon-exclamation-sign'}
-        ],
-        isNoOsChecked: false,
-        m: 'two with empty-error, two with validation="icon-exclamation-sign"',
-        e: 4
-      },
-      {
-        allRepositories: [
-          {}
-        ],
-        isNoOsChecked: false,
-        m: 'no errors/warnings etc',
-        e: 0
-      }
-    ]);
-    tests.forEach(function (test) {
-      it(test.m, function () {
-        view = App.WizardStep1View.create();
-        view.reopen({
-          isNoOsChecked: test.isNoOsChecked,
-          allRepositories: test.allRepositories
-        });
-        expect(view.get('totalErrorCnt')).to.equal(test.e);
-      });
-    });
-  });
-
-  describe('#didInsertElement', function () {
-
-    beforeEach(function () {
-      sinon.stub($.fn, 'tooltip', Em.K);
-    });
-
-    afterEach(function () {
-      $.fn.tooltip.restore();
-    });
-
-    it('should create tooltip', function () {
-      view.set('isRLCollapsed', false);
-      view.didInsertElement();
-      expect($.fn.tooltip.calledOnce).to.equal(true);
-    });
-  });
-
-  describe('#stackRadioButton', function () {
-
-    var v;
-    beforeEach(function () {
-      v = view.get('stackRadioButton').create({
-        content: Em.Object.create({
-          name: ''
-        }),
-        controller: Em.Object.create({
-          content: Em.Object.create({
-            stacks: []
-          })
-        })
-      });
-    });
-
-    describe('#isSelected', function () {
-      it('should be equal content.isSelected', function () {
-        v.set('content.isSelected', true);
-        expect(v.get('checked')).to.equal(true);
-        v.set('content.isSelected', false);
-        expect(v.get('checked')).to.equal(false);
-      });
-    });
-
-    describe('#click', function () {
-      it('should select proper stack', function () {
-        v.set('controller.content.stacks', Em.A([Em.Object.create({id: 'n-1'}), Em.Object.create({id: 'n-2'}), Em.Object.create({id: 'n-3'})]));
-        v.set('content.name', 'n 2');
-        v.click();
-        expect(v.get('controller.content.stacks').getEach('isSelected')).to.eql([false, true, false]);
-      });
-    });
-
-  });
-
-  describe('#popoverView', function () {
-
-    var v;
-    beforeEach(function () {
-      v = view.get('popoverView').create();
-      sinon.stub(App, 'popover', Em.K);
-      view = App.WizardStep1View.create({'controller': controller});
-      view.set('$', function () {
-        return Em.Object.create({hide: Em.K, toggle: Em.K});
-      });
-    });
-
-    afterEach(function () {
-      App.popover.restore();
-    });
-
-    describe('#didInsertElement', function () {
-      it('should create popover', function () {
-        v.didInsertElement();
-        expect(App.popover.calledOnce).to.equal(true);
-      });
-    });
-
-  });
-
-  describe('#onToggleBlock', function () {
-
-    it('should toggle isRLCollapsed', function () {
-      view.set('isRLCollapsed', true);
-      view.onToggleBlock();
-      expect(view.get('isRLCollapsed')).to.equal(false);
-      view.onToggleBlock();
-      expect(view.get('isRLCollapsed')).to.equal(true);
-    });
-  });
-
-  describe('#updateByCheckbox', function () {
-
-    var operatingSystems = [
-      Em.Object.create({
-        name: 'redhat5',
-        isSelected: false,
-        repositories: [Em.Object.create({
-          id: 'id',
-          osType: 'redhat5',
-          baseUrl: 'baseUrl',
-          latestBaseUrl: 'latestBaseUrl',
-          validation: '',
-          isSelected: false
-        })
-        ]
-      })
-    ];
-
-    var ctrl = {
-      content: {
-        stacks: [
-          Em.Object.create({
-            isSelected: true,
-            operatingSystems: [
-              Em.Object.create({
-                id: 'id',
-                osType: 'redhat5',
-                baseUrl: 'baseUrl',
-                latestBaseUrl: 'latestBaseUrl',
-                validation: '',
-                isSelected: false
-              })
-            ]
-          })
-        ]
-      },
-      selectedStack: Em.Object.create({
-        isSelected: true,
-        operatingSystems: [
-          Em.Object.create({
-            id: 'id',
-            osType: 'redhat5',
-            baseUrl: 'baseUrl',
-            latestBaseUrl: 'latestBaseUrl',
-            validation: '',
-            isSelected: true
-          })
-        ]
-      }),
-      skipValidationChecked: true
-    };
-
-    it('target group isn\'t isSelected', function () {
-      view.reopen({
-        operatingSystems: operatingSystems,
-        controller: ctrl
-      });
-      view.updateByCheckbox();
-      var targetGroup = view.get('operatingSystems.firstObject.repositories.firstObject');
-      expect(targetGroup.get('baseUrl')).to.equal('latestBaseUrl');
-      expect(targetGroup.get('latestBaseUrl')).to.equal('latestBaseUrl');
-      expect(targetGroup.get('validation')).to.be.empty;
-
-    });
-
-    it('target group is isSelected, skipValidationisSelected = true', function () {
-      ctrl.content.stacks[0].operatingSystems[0].selected = true;
-      operatingSystems[0].set('isSelected', true);
-      view.reopen({
-        operatingSystems: operatingSystems,
-        controller: ctrl
-      });
-      view.updateByCheckbox();
-      var targetGroup = view.get('operatingSystems.firstObject.repositories.firstObject');
-      expect(targetGroup.get('validation')).to.be.empty;
-    });
-  });
-
-  describe('#clearGroupLocalRepository', function () {
-    var context = {'group-number': 0, id: 'HDP-redhat5', repoId: 'HDP-redhat5', baseUrl: 'baseUrl', validation: 'validation'};
-    it('should empty base url and validation', function () {
-      var event = {context: Em.Object.create(context, {isSelected: true})};
-      view.clearGroupLocalRepository(event);
-      expect(event.context.get('baseUrl')).to.be.empty;
-      expect(event.context.get('validation')).to.be.empty;
-    });
-    it('should do nothing if corresponding OS is not selected', function () {
-      var event = {context: Em.Object.create(context, {isSelected: false})};
-      view.clearGroupLocalRepository(event);
-      expect(event.context.get('baseUrl')).to.equal('baseUrl');
-      expect(event.context.get('validation')).to.equal('validation');
-    });
-  });
-
-  describe('#undoGroupLocalRepository', function () {
-    it('should reset base url and validation', function () {
-      var event = {context: Em.Object.create({'group-number': 0, id: 'HDP-redhat5', repoId: 'HDP-redhat5', latestBaseUrl: 'latestBaseUrl', validation: 'validation'})};
-      view.undoGroupLocalRepository(event);
-      expect(event.context.get('baseUrl')).to.equal(event.context.get('latestBaseUrl'));
-      expect(event.context.get('validation')).to.be.empty;
-    });
-  });
 
   describe('#editLocalRepository', function () {