public void createAmbariResources(ClusterTopology topology, String clusterName, SecurityType securityType,
                                    String repoVersionString, Long repoVersionId) {
    Stack stack = topology.getBlueprint().getStack();
    StackId stackId = new StackId(stack.getName(), stack.getVersion());

    RepositoryVersionEntity repoVersion = null;
    if (StringUtils.isEmpty(repoVersionString) && null == repoVersionId) {
      List<RepositoryVersionEntity> stackRepoVersions = repositoryVersionDAO.findByStack(stackId);

      if (stackRepoVersions.isEmpty()) {
        // !!! no repos, try to get the version for the stack
        VersionDefinitionResourceProvider vdfProvider = getVersionDefinitionResourceProvider();

        Map<String, Object> properties = new HashMap<>();
        properties.put(VersionDefinitionResourceProvider.VERSION_DEF_AVAILABLE_DEFINITION, stackId.toString());

        Request request = new RequestImpl(Collections.<String>emptySet(),
            Collections.singleton(properties), Collections.<String, String>emptyMap(), null);

        Long defaultRepoVersionId = null;

        try {
          RequestStatus requestStatus = vdfProvider.createResources(request);
          if (!requestStatus.getAssociatedResources().isEmpty()) {
            Resource resource = requestStatus.getAssociatedResources().iterator().next();
            defaultRepoVersionId = (Long) resource.getPropertyValue(VersionDefinitionResourceProvider.VERSION_DEF_ID);
          }
        } catch (Exception e) {
          throw new IllegalArgumentException(String.format(
              "Failed to create a default repository version definition for stack %s. "
              + "This typically is a result of not loading the stack correctly or being able "
              + "to load information about released versions.  Create a repository version "
              + " and try again.", stackId), e);
        }

        repoVersion = repositoryVersionDAO.findByPK(defaultRepoVersionId);
        // !!! better not!
        if (null == repoVersion) {
          throw new IllegalArgumentException(String.format(
              "Failed to load the default repository version definition for stack %s. "
              + "Check for a valid repository version and try again.", stackId));
        }

      } else if (stackRepoVersions.size() > 1) {

        Function<RepositoryVersionEntity, String> function = new Function<RepositoryVersionEntity, String>() {
          @Override
          public String apply(RepositoryVersionEntity input) {
            return input.getVersion();
          }
        };

        Collection<String> versions = Collections2.transform(stackRepoVersions, function);

        throw new IllegalArgumentException(String.format("Several repositories were found for %s:  %s.  Specify the version"
            + " with '%s'", stackId, StringUtils.join(versions, ", "), ProvisionClusterRequest.REPO_VERSION_PROPERTY));
      } else {
        repoVersion = stackRepoVersions.get(0);
        LOG.warn("Cluster is being provisioned using the single matching repository version {}", repoVersion.getVersion());
      }
    } else {
      if (null != repoVersionId) {
        repoVersion = repositoryVersionDAO.findByPK(repoVersionId);

        if (null == repoVersion) {
          throw new IllegalArgumentException(String.format(
            "Could not identify repository version with repository version id %s for installing services. "
              + "Specify a valid repository version id with '%s'",
            repoVersionId, ProvisionClusterRequest.REPO_VERSION_ID_PROPERTY));
        }
      } else {
        repoVersion = repositoryVersionDAO.findByStackAndVersion(stackId, repoVersionString);

        if (null == repoVersion) {
          throw new IllegalArgumentException(String.format(
            "Could not identify repository version with stack %s and version %s for installing services. "
              + "Specify a valid version with '%s'",
            stackId, repoVersionString, ProvisionClusterRequest.REPO_VERSION_PROPERTY));
        }
      }

      if (!Objects.equals(repoVersion.getStackId(), stackId)) {
        String repoVersionPair = repoVersionId != null
          ? String.format("'%s' = %d", ProvisionClusterRequest.REPO_VERSION_ID_PROPERTY, repoVersionId)
          : String.format("'%s' = '%s'", ProvisionClusterRequest.REPO_VERSION_PROPERTY, repoVersionString);
        String msg = String.format(
          "The stack specified in the blueprint (%s) and the repository version (%s for %s) should match",
          stackId, repoVersion.getStackId(), repoVersionPair);
        throw new IllegalArgumentException(msg);
      }
    }

    // only use a STANDARD repo when creating a new cluster
    if (repoVersion.getType() != RepositoryType.STANDARD) {
      throw new IllegalArgumentException(String.format(
          "Unable to create a cluster using the following repository since it is not a STANDARD type: %s",
          repoVersion));
    }

    createAmbariClusterResource(clusterName, stack.getName(), stack.getVersion(), securityType);
    createAmbariServiceAndComponentResources(topology, clusterName, stackId, repoVersion.getId());
  }
When config groups are created using Blueprints these are created when
hosts join a hostgroup and are added to the corresponding config group.
Since hosts join in parallel there might be a race condition in creating
the config group a host is to be added to. Thus we need to synchronize
the creation of config groups with the same name.
ambari-server/src/main/java/org/apache/ambari/server/topology/AmbariContext.java