You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ja...@apache.org on 2014/11/19 07:42:02 UTC

[1/2] ambari git commit: AMBARI-7448. Create Kerberos Service. (Robert Levas via jaimin)

Repository: ambari
Updated Branches:
  refs/heads/trunk defa49b78 -> 6fbfdb4a0


http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/test/python/stacks/2.2/KERBEROS/use_cases.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.2/KERBEROS/use_cases.py b/ambari-server/src/test/python/stacks/2.2/KERBEROS/use_cases.py
new file mode 100644
index 0000000..0634a37
--- /dev/null
+++ b/ambari-server/src/test/python/stacks/2.2/KERBEROS/use_cases.py
@@ -0,0 +1,231 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+import json
+
+krb5_conf_template = \
+  '[libdefaults]\n' \
+  '  renew_lifetime = {{libdefaults_renew_lifetime}}\n' \
+  '  forwardable = {{libdefaults_forwardable}}\n' \
+  '  default_realm = {{realm|upper()}}\n' \
+  '  ticket_lifetime = {{libdefaults_ticket_lifetime}}\n' \
+  '  dns_lookup_realm = {{libdefaults_dns_lookup_realm}}\n' \
+  '  dns_lookup_kdc = {{libdefaults_dns_lookup_kdc}}\n' \
+  '\n' \
+  '{% if domains %}\n' \
+  '[domain_realm]\n' \
+  '{% for domain in domains %}\n' \
+  '  {{domain}} = {{realm|upper()}}\n' \
+  '{% endfor %}\n' \
+  '{% endif %}\n' \
+  '\n' \
+  '[logging]\n' \
+  '  default = {{logging_default}}\n' \
+  '{#\n' \
+  ' # The following options are unused unless a managed KDC is installed\n' \
+  '  admin_server = {{logging_admin_server}}\n' \
+  'kdc = {{logging_admin_kdc}}\n' \
+  '#}\n' \
+  '[realms]\n' \
+  '  {{realm}} = {\n' \
+  '    admin_server = {{admin_server_host|default(kdc_host, True)}}\n' \
+  '    kdc = {{kdc_host}}\n' \
+  '}\n' \
+  '\n' \
+  '{# Append additional realm declarations should be placed below #}\n'
+
+kdc_conf_template = \
+  '[kdcdefaults]\n' \
+  '  kdc_ports = {{kdcdefaults_kdc_ports}}\n' \
+  '  kdc_tcp_ports = {{kdcdefaults_kdc_tcp_ports}}\n' \
+  '\n' \
+  '[realms]\n' \
+  '  {{realm}} = {\n' \
+  '    acl_file = {{kadm5_acl_path}}\n' \
+  '    dict_file = /usr/share/dict/words\n' \
+  '    admin_keytab = {{kadm5_acl_dir}}/kadm5.keytab\n' \
+  '    supported_enctypes = {{libdefaults_default_tgs_enctypes}}\n' \
+  '}\n' \
+  '\n' \
+  '{# Append additional realm declarations should be placed below #}\n'
+
+kadm5_acl_template = '*/admin@{{realm}}	*'
+
+
+def get_manged_kdc_use_case():
+  config_file = "stacks/2.2/configs/default.json"
+  with open(config_file, "r") as f:
+    json_data = json.load(f)
+
+  json_data['clusterHostInfo']['kdc_server_hosts'] = ['c6401.ambari.apache.org']
+  json_data['configurations']['krb5-conf'] = {
+    'libdefaults_default_tgs_enctypes': 'aes256-cts-hmac-sha1-96',
+    'libdefaults_default_tkt_enctypes': 'aes256-cts-hmac-sha1-96',
+    'realm': 'MANAGED_REALM.COM',
+    'kdc_type': 'mit-kdc',
+    'kdc_host': 'c6401.ambari.apache.org',
+    'admin_principal': "admin/admin",
+    'admin_password': "hadoop"
+  }
+
+  return json_data
+
+
+def get_unmanged_kdc_use_case():
+  config_file = "stacks/2.2/configs/default.json"
+  with open(config_file, "r") as f:
+    json_data = json.load(f)
+
+  json_data['configurations']['krb5-conf'] = {
+    'libdefaults_default_tgs_enctypes': 'aes256-cts-hmac-sha1-96',
+    'libdefaults_default_tkt_enctypes': 'aes256-cts-hmac-sha1-96',
+    'conf_dir': '/tmp',
+    'conf_file': 'krb5_unmanaged.conf',
+    'content': krb5_conf_template,
+    'realm': 'OSCORPINDUSTRIES.COM',
+    'kdc_type': 'mit-kdc',
+    'kdc_host': 'ad.oscorp_industries.com',
+    'admin_principal': "admin/admin",
+    'admin_password': "hadoop"
+  }
+  json_data['configurations']['kdc-conf'] = {
+    'content': kdc_conf_template
+  }
+  json_data['configurations']['kadm5-acl'] = {
+    'content': kadm5_acl_template
+  }
+
+  return json_data
+
+def get_unmanged_ad_use_case():
+  config_file = "stacks/2.2/configs/default.json"
+  with open(config_file, "r") as f:
+    json_data = json.load(f)
+
+  json_data['configurations']['krb5-conf'] = {
+    'libdefaults_default_tgs_enctypes': 'aes256-cts-hmac-sha1-96',
+    'libdefaults_default_tkt_enctypes': 'aes256-cts-hmac-sha1-96',
+    'conf_dir': '/tmp',
+    'conf_file': 'krb5_ad.conf',
+    'content': krb5_conf_template,
+    'realm': 'OSCORPINDUSTRIES.COM',
+    'kdc_type': 'active-directory',
+    'kdc_host': 'ad.oscorp_industries.com',
+    'admin_principal': "admin/admin",
+    'admin_password': "hadoop"
+  }
+  json_data['configurations']['kdc-conf'] = {
+    'content': kdc_conf_template
+  }
+  json_data['configurations']['kadm5-acl'] = {
+    'content': kadm5_acl_template
+  }
+
+  return json_data
+
+def get_cross_realm_use_case():
+  config_file = "stacks/2.2/configs/default.json"
+  with open(config_file, "r") as f:
+    json_data = json.load(f)
+
+  _krb5_conf_template = krb5_conf_template + \
+                        '' \
+                        '  OSCORPINDUSTRIES.COM = {\n' \
+                        '    kdc = ad.oscorp_industries.com\n' \
+                        '}\n'
+
+  json_data['clusterHostInfo']['kdc_server_hosts'] = ['c6401.ambari.apache.org']
+  json_data['configurations']['krb5-conf'] = {
+    'libdefaults_default_tgs_enctypes': 'aes256-cts-hmac-sha1-96',
+    'libdefaults_default_tkt_enctypes': 'aes256-cts-hmac-sha1-96',
+    'content': _krb5_conf_template,
+    'realm': 'MANAGED_REALM.COM',
+    'kdc_type': 'mit-kdc',
+    'kdc_host': 'c6401.ambari.apache.org',
+    'admin_principal': "admin/admin",
+    'admin_password': "hadoop"
+  }
+  json_data['configurations']['kdc-conf'] = {
+    'content': kdc_conf_template
+  }
+  json_data['configurations']['kadm5-acl'] = {
+    'content': kadm5_acl_template
+  }
+
+  return json_data
+
+def get_value(dictionary, path, nullValue=None):
+  if (dictionary is None) or (path is None) or (len(path) == 0):
+    return nullValue
+  else:
+    name = path.pop()
+
+    if name in dictionary:
+      value = dictionary[name]
+
+      if len(path) == 0:
+        return value
+      else:
+        return get_value(value, path, nullValue)
+    else:
+      return nullValue
+
+def get_krb5_conf_path(json_data):
+  return get_value(json_data,
+                   ['conf_path', 'krb5-conf', 'configurations'],
+                   get_krb5_conf_dir(json_data) + '/' + get_krb5_conf_file(json_data))
+
+def get_krb5_conf_file(json_data):
+  return get_value(json_data, ['conf_file', 'krb5-conf', 'configurations'], 'krb5.conf')
+
+def get_krb5_conf_dir(json_data):
+  return get_value(json_data, ['conf_dir', 'krb5-conf', 'configurations'], '/etc')
+
+def get_krb5_conf_template(json_data):
+  return get_value(json_data, ['content', 'krb5-conf', 'configurations'], None)
+
+def get_kdc_conf_path(json_data):
+  return get_value(json_data,
+                   ['conf_path', 'kdc-conf', 'configurations'],
+                   get_kdc_conf_dir(json_data) + '/' + get_kdc_conf_file(json_data))
+
+def get_kdc_conf_file(json_data):
+  return get_value(json_data, ['conf_file', 'kdc-conf', 'configurations'], 'kdc.conf')
+
+def get_kdc_conf_dir(json_data):
+  return get_value(json_data, ['conf_dir', 'kdc-conf', 'configurations'],
+                   '/var/lib/kerberos/krb5kdc')
+
+def get_kdc_conf_template(json_data):
+  return get_value(json_data, ['content', 'kdc-conf', 'configurations'], None)
+
+def get_kadm5_acl_path(json_data):
+  return get_value(json_data,
+                   ['conf_path', 'kadm5-acl', 'configurations'],
+                   get_kadm5_acl_dir(json_data) + '/' + get_kadm5_acl_file(json_data))
+
+def get_kadm5_acl_file(json_data):
+  return get_value(json_data, ['conf_file', 'kadm5-acl', 'configurations'], 'kadm5.acl')
+
+def get_kadm5_acl_dir(json_data):
+  return get_value(json_data, ['conf_dir', 'kadm5-acl', 'configurations'],
+                   '/var/lib/kerberos/krb5kdc')
+
+def get_kadm5_acl_template(json_data):
+  return get_value(json_data, ['content', 'kadm5-acl', 'configurations'], None)


[2/2] ambari git commit: AMBARI-7448. Create Kerberos Service. (Robert Levas via jaimin)

Posted by ja...@apache.org.
AMBARI-7448. Create Kerberos Service. (Robert Levas via jaimin)


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

Branch: refs/heads/trunk
Commit: 6fbfdb4a0774b64ca92760747e90f9de01db5542
Parents: defa49b
Author: Jaimin Jetly <ja...@hortonworks.com>
Authored: Tue Nov 18 22:41:25 2014 -0800
Committer: Jaimin Jetly <ja...@hortonworks.com>
Committed: Tue Nov 18 22:41:25 2014 -0800

----------------------------------------------------------------------
 .../java/org/apache/ambari/server/Role.java     |   3 +
 .../KERBEROS/configuration/kadm5-acl.xml        |  36 ++
 .../KERBEROS/configuration/kdc-conf.xml         |  57 +++
 .../KERBEROS/configuration/krb5-conf.xml        | 186 +++++++++
 .../HDP/2.2/services/KERBEROS/metainfo.xml      | 167 ++++++++
 .../KERBEROS/package/scripts/kerberos_client.py |  40 ++
 .../KERBEROS/package/scripts/kerberos_common.py | 398 +++++++++++++++++++
 .../KERBEROS/package/scripts/kerberos_server.py | 144 +++++++
 .../services/KERBEROS/package/scripts/params.py | 197 +++++++++
 .../KERBEROS/package/scripts/service_check.py   |  63 +++
 .../services/KERBEROS/package/scripts/utils.py  |  69 ++++
 .../KERBEROS/package/templates/kadm5_acl.j2     |  20 +
 .../KERBEROS/package/templates/kdc_conf.j2      |  30 ++
 .../KERBEROS/package/templates/krb5_conf.j2     |  47 +++
 .../services/KerberosServiceMetaInfoTest.java   | 283 +++++++++++++
 .../stacks/2.2/KERBEROS/test_kerberos_client.py | 117 ++++++
 .../stacks/2.2/KERBEROS/test_kerberos_server.py | 248 ++++++++++++
 .../python/stacks/2.2/KERBEROS/use_cases.py     | 231 +++++++++++
 18 files changed, 2336 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/java/org/apache/ambari/server/Role.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/Role.java b/ambari-server/src/main/java/org/apache/ambari/server/Role.java
index 61a2fb9..45a9ac5 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/Role.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/Role.java
@@ -104,6 +104,9 @@ public class Role {
   public static final Role FALCON_SERVICE_CHECK = valueOf("FALCON_SERVICE_CHECK");
   public static final Role STORM_SERVICE_CHECK = valueOf("STORM_SERVICE_CHECK");
   public static final Role YARN_CLIENT = valueOf("YARN_CLIENT");
+  public static final Role KDC_SERVER = valueOf("KDC_SERVER");
+  public static final Role KERBEROS_CLIENT = valueOf("KERBEROS_CLIENT");
+  public static final Role KERBEROS_SERVICE_CHECK = valueOf("KERBEROS_SERVICE_CHECK");
 
   private String name = null;
   

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kadm5-acl.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kadm5-acl.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kadm5-acl.xml
new file mode 100644
index 0000000..44cce66
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kadm5-acl.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+  ~ 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
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<configuration>
+  <property>
+    <name>conf_dir</name>
+    <description>The kadm.acl configuration directory</description>
+    <value>/var/kerberos/krb5kdc</value>
+  </property>
+  <property>
+    <name>content</name>
+    <description>The jinja template for the kadm5.acl file</description>
+    <value>
+      */admin@{{realm}}	*
+
+      {# Append additional realm declarations should be placed below #}
+    </value>
+  </property>
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kdc-conf.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kdc-conf.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kdc-conf.xml
new file mode 100644
index 0000000..ff8b9fb
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/kdc-conf.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+/**
+ * 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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<configuration>
+  <property>
+    <name>kdcdefaults_kdc_ports</name>
+    <value>88</value>
+  </property>
+  <property>
+    <name>kdcdefaults_kdc_tcp_ports</name>
+    <value>88</value>
+  </property>
+
+  <property>
+    <name>conf_dir</name>
+    <description>The kdc.conf configuration directory</description>
+    <value>/var/kerberos/krb5kdc</value>
+  </property>
+  <property>
+    <name>content</name>
+    <description>The jinja template for the kdc.conf file</description>
+    <value>
+      [kdcdefaults]
+        kdc_ports = {{kdcdefaults_kdc_ports}}
+        kdc_tcp_ports = {{kdcdefaults_kdc_tcp_ports}}
+
+      [realms]
+        {{realm}} = {
+          acl_file = {{kadm5_acl_path}}
+          dict_file = /usr/share/dict/words
+          admin_keytab = {{kadm5_acl_dir}}/kadm5.keytab
+          supported_enctypes = {{libdefaults_default_tgs_enctypes}}
+      }
+
+      {# Append additional realm declarations should be placed below #}
+    </value>
+  </property>
+</configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/krb5-conf.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/krb5-conf.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/krb5-conf.xml
new file mode 100644
index 0000000..4f3ddbd
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/configuration/krb5-conf.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+/**
+ * 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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<configuration>
+  <property>
+    <name>logging_default</name>
+    <value>FILE:/var/log/krb5libs.log</value>
+  </property>
+  <property>
+    <name>logging_kdc</name>
+    <value>FILE:/var/log/krb5kdc.log</value>
+  </property>
+  <property>
+    <name>logging_admin_server</name>
+    <value>FILE:/var/log/kadmind.log</value>
+  </property>
+
+  <property>
+    <name>libdefaults_dns_lookup_realm</name>
+    <value>false</value>
+  </property>
+  <property>
+    <name>libdefaults_dns_lookup_kdc</name>
+    <value>false</value>
+  </property>
+  <property>
+    <name>libdefaults_ticket_lifetime</name>
+    <value>24h</value>
+  </property>
+  <property>
+    <name>libdefaults_renew_lifetime</name>
+    <value>7d</value>
+  </property>
+  <property>
+    <name>libdefaults_forwardable</name>
+    <value>true</value>
+  </property>
+  <property>
+    <name>libdefaults_default_tgs_enctypes</name>
+    <description>
+      a space-delimited list of session key encryption types supported by the KDC or Active
+      Directory
+    </description>
+    <value>
+      aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5
+      camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
+    </value>
+  </property>
+  <property>
+    <name>libdefaults_default_tkt_enctypes</name>
+    <description>
+      a space-delimited list of session key encryption types supported by the KDC or Active
+      Directory
+    </description>
+    <value>
+      aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5
+      camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
+    </value>
+  </property>
+
+  <property require-input="true">
+    <name>realm</name>
+    <description>
+      The realm to use when creating service principals
+    </description>
+    <value/>
+  </property>
+  <property require-input="true">
+    <name>domains</name>
+    <description>
+      A comma-delimited list of domain names that the realm serves (optional)
+    </description>
+    <value/>
+  </property>
+  <property require-input="true">
+    <name>kdc_type</name>
+    <description>
+      The type of KDC being used. Either mit-kdc or active-directory
+    </description>
+    <value>mit-kdc</value>
+  </property>
+  <property require-input="true">
+    <name>kdc_host</name>
+    <description>
+      The IP address or FQDN of the KDC or Active Directory server, optionally a port number may be
+      provided
+    </description>
+    <value/>
+  </property>
+  <property>
+    <name>admin_server_host</name>
+    <description>
+      The IP address or FQDN of the administrative Kerberos server, optionally a port number may be
+      provided
+    </description>
+    <value/>
+  </property>
+  <property>
+    <name>test_principal</name>
+    <description>
+      The principal that may be used to test the Kerberos configuration (this will not be retained)
+    </description>
+    <value/>
+  </property>
+  <property>
+    <name>test_password</name>
+    <description>
+      The password for the administrative principal (either this value or the keytab value is
+      required to be set, neither is expected to be retained)
+    </description>
+    <value/>
+    <property-type>PASSWORD</property-type>
+  </property>
+  <property>
+    <name>test_keytab</name>
+    <description>
+      The base64-encoded keytab for the test principal (either this value or the password
+      value is required to be set, neither is expected to be retained)
+    </description>
+    <value>
+
+    </value>
+  </property>
+
+
+  <property>
+    <name>conf_dir</name>
+    <description>The krb5.conf configuration directory</description>
+    <value>/etc</value>
+  </property>
+  <property>
+    <name>content</name>
+    <description>The jinja template for the krb5.conf file</description>
+    <value>
+[libdefaults]
+  renew_lifetime = {{libdefaults_renew_lifetime}}
+  forwardable = {{libdefaults_forwardable}}
+  default_realm = {{realm|upper()}}
+  ticket_lifetime = {{libdefaults_ticket_lifetime}}
+  dns_lookup_realm = {{libdefaults_dns_lookup_realm}}
+  dns_lookup_kdc = {{libdefaults_dns_lookup_kdc}}
+
+{% if domains %}
+[domain_realm]
+{% for domain in domains %}
+  {{domain}} = {{realm|upper()}}
+{% endfor %}
+{% endif %}
+
+[logging]
+  default = {{logging_default}}
+{#
+# The following options are unused unless a managed KDC is installed
+  admin_server = {{logging_admin_server}}
+  kdc = {{logging_admin_kdc}}
+#}
+
+[realms]
+  {{realm}} = {
+    admin_server = {{admin_server_host|default(kdc_host, True)}}
+    kdc = {{kdc_host}}
+  }
+
+{# Append additional realm declarations should be placed below #}
+    </value>
+  </property>
+</configuration>

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml
new file mode 100644
index 0000000..8751892
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/metainfo.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0"?>
+<!--
+   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 regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<metainfo>
+  <schemaVersion>2.0</schemaVersion>
+  <services>
+    <service>
+      <name>KERBEROS</name>
+      <displayName>Kerberos</displayName>
+      <comment>A computer network authentication protocol which works on
+        the basis of 'tickets' to allow nodes communicating over a
+        non-secure network to prove their identity to one another in a
+        secure manner.
+      </comment>
+      <version>1.10.3-10</version>
+
+      <components>
+        <component>
+          <name>KDC_SERVER</name>
+          <displayName>Kerberos KDC</displayName>
+          <category>MASTER</category>
+          <cardinality>0-1</cardinality>
+          <dependencies>
+            <dependency>
+              <name>KERBEROS/KERBEROS_CLIENT</name>
+              <scope>cluster</scope>
+              <auto-deploy>
+                <enabled>true</enabled>
+              </auto-deploy>
+            </dependency>
+          </dependencies>
+          <commandScript>
+            <script>scripts/kerberos_server.py</script>
+            <scriptType>PYTHON</scriptType>
+            <timeout>900</timeout>
+          </commandScript>
+          <configFiles>
+            <configFile>
+              <type>env</type>
+              <fileName>krb5.conf</fileName>
+              <dictionaryName>krb5-conf</dictionaryName>
+            </configFile>
+            <configFile>
+              <type>env</type>
+              <fileName>kdc.conf</fileName>
+              <dictionaryName>kdc-conf</dictionaryName>
+            </configFile>
+            <configFile>
+              <type>env</type>
+              <fileName>kadm5.acl</fileName>
+              <dictionaryName>kadm5-acl</dictionaryName>
+            </configFile>
+          </configFiles>
+        </component>
+
+        <component>
+          <name>KERBEROS_CLIENT</name>
+          <displayName>Kerberos Client</displayName>
+          <category>CLIENT</category>
+          <cardinality>ALL</cardinality>
+          <auto-deploy>
+            <enabled>true</enabled>
+          </auto-deploy>
+          <commandScript>
+            <script>scripts/kerberos_client.py</script>
+            <scriptType>PYTHON</scriptType>
+            <timeout>600</timeout>
+          </commandScript>
+          <customCommands>
+            <customCommand>
+              <name>SET_KEYTAB</name>
+              <commandScript>
+                <script>scripts/kerberos_client.py</script>
+                <scriptType>PYTHON</scriptType>
+                <timeout>1000</timeout>
+              </commandScript>
+            </customCommand>
+          </customCommands>
+          <configFiles>
+            <configFile>
+              <type>env</type>
+              <fileName>krb5.conf</fileName>
+              <dictionaryName>krb5-conf</dictionaryName>
+            </configFile>
+          </configFiles>
+        </component>
+      </components>
+
+      <osSpecifics>
+        <osSpecific>
+          <osFamily>redhat5,redhat6</osFamily>
+          <packages>
+            <package>
+              <name>krb5-server</name>
+            </package>
+            <package>
+              <name>krb5-libs</name>
+            </package>
+            <package>
+              <name>krb5-workstation</name>
+            </package>
+          </packages>
+        </osSpecific>
+
+        <osSpecific>
+          <osFamily>ubuntu12</osFamily>
+          <packages>
+            <package>
+              <name>krb5-kdc</name>
+            </package>
+            <package>
+              <name>krb5-admin-server</name>
+            </package>
+            <package>
+              <name>krb5-user</name>
+            </package>
+            <package>
+              <name>krb5-config</name>
+            </package>
+          </packages>
+        </osSpecific>
+
+        <osSpecific>
+          <osFamily>suse11</osFamily>
+          <packages>
+            <package>
+              <name>krb5</name>
+            </package>
+            <package>
+              <name>krb5-client</name>
+            </package>
+            <package>
+              <name>krb5-server</name>
+            </package>
+          </packages>
+        </osSpecific>
+      </osSpecifics>
+
+      <commandScript>
+        <script>scripts/service_check.py</script>
+        <scriptType>PYTHON</scriptType>
+        <timeout>300</timeout>
+      </commandScript>
+
+      <configuration-dependencies>
+        <config-type>krb5-conf</config-type>
+        <config-type>kdc-conf</config-type>
+        <config-type>kadm5-acl</config-type>
+      </configuration-dependencies>
+      <restartRequiredAfterChange>true</restartRequiredAfterChange>
+    </service>
+  </services>
+</metainfo>

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_client.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_client.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_client.py
new file mode 100644
index 0000000..a341e8d
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_client.py
@@ -0,0 +1,40 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+from kerberos_common import *
+
+class KerberosClient(KerberosScript):
+  def install(self, env):
+    self.install_packages(env, ['krb5-server', 'krb5-libs', 'krb5-auth-dialog', 'krb5', 'krb5-kdc', 'krb5-admin-server'])
+    self.configure(env)
+
+
+  def configure(self, env):
+    import params
+    env.set_params(params)
+    self.write_krb5_conf()
+
+  def status(self, env):
+    raise ClientComponentHasNoStatus()
+
+  def set_keytab(self, env):
+    KerberosScript.write_keytab_file()
+
+if __name__ == "__main__":
+  KerberosClient().execute()

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_common.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_common.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_common.py
new file mode 100644
index 0000000..269658b
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_common.py
@@ -0,0 +1,398 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+import base64
+import os
+import string
+import subprocess
+import sys
+import tempfile
+
+from resource_management import *
+from utils import get_property_value
+
+class KerberosScript(Script):
+  KRB5_REALM_PROPERTIES = [
+    'kdc',
+    'admin_server',
+    'default_domain',
+    'master_kdc'
+  ]
+
+  KRB5_SECTION_NAMES = [
+    'libdefaults',
+    'logging',
+    'realms',
+    'domain_realm',
+    'capaths',
+    'ca_paths',
+    'appdefaults',
+    'plugins'
+  ]
+
+  @staticmethod
+  def create_random_password():
+    import random
+
+    chars = string.digits + string.ascii_letters
+    return ''.join(random.choice(chars) for x in range(13))
+
+  @staticmethod
+  def write_conf_section(output_file, section_name, section_data):
+    if section_name is not None:
+      output_file.write('[%s]\n' % section_name)
+
+      if section_data is not None:
+        for key, value in section_data.iteritems():
+          output_file.write(" %s = %s\n" % (key, value))
+
+
+  @staticmethod
+  def _write_conf_realm(output_file, realm_name, realm_data):
+    """ Writes out realm details
+
+    Example:
+
+     EXAMPLE.COM = {
+      kdc = kerberos.example.com
+      admin_server = kerberos.example.com
+     }
+
+    """
+    if realm_name is not None:
+      output_file.write(" %s = {\n" % realm_name)
+
+      if realm_data is not None:
+        for key, value in realm_data.iteritems():
+          if key in KerberosScript.KRB5_REALM_PROPERTIES:
+            output_file.write("  %s = %s\n" % (key, value))
+
+      output_file.write(" }\n")
+
+  @staticmethod
+  def write_conf_realms_section(output_file, section_name, realms_data):
+    if section_name is not None:
+      output_file.write('[%s]\n' % section_name)
+
+      if realms_data is not None:
+        for realm, realm_data in realms_data.iteritems():
+          KerberosScript._write_conf_realm(output_file, realm, realm_data)
+          output_file.write('\n')
+
+  @staticmethod
+  def write_krb5_conf():
+    import params
+
+    Directory(params.krb5_conf_dir,
+              owner='root',
+              recursive=True,
+              group='root',
+              mode=0755
+    )
+
+    if (params.krb5_conf_template is None) or not params.krb5_conf_template.strip():
+      content = Template('krb5_conf.j2')
+    else:
+      content = InlineTemplate(params.krb5_conf_template)
+
+    File(params.krb5_conf_path,
+         content=content,
+         owner='root',
+         group='root',
+         mode=0644
+    )
+
+  @staticmethod
+  def invoke_kadmin(query, admin_identity=None, default_realm=None):
+    """
+    Executes the kadmin or kadmin.local command (depending on whether auth_identity is set or not
+    and returns command result code and standard out data.
+
+    :param query: the kadmin query to execute
+    :param admin_identity: the identity for the administrative user (optional)
+    :param default_realm: the default realm to assume
+    :return: return_code, out
+    """
+    if (query is not None) and (len(query) > 0):
+      auth_principal = None
+      auth_keytab_file = None
+
+      if admin_identity is not None:
+        auth_principal = get_property_value(admin_identity, 'principal')
+
+      if auth_principal is None:
+        kadmin = 'kadmin.local'
+        credential = ''
+      else:
+        kadmin = 'kadmin -p "%s"' % auth_principal
+
+        auth_password = get_property_value(admin_identity, 'password')
+
+        if auth_password is None:
+          auth_keytab = get_property_value(admin_identity, 'keytab')
+
+          if auth_keytab is not None:
+            (fd, auth_keytab_file) = tempfile.mkstemp()
+            os.write(fd, base64.b64decode(auth_keytab))
+            os.close(fd)
+
+          credential = '-k -t %s' % auth_keytab_file
+        else:
+          credential = '-w "%s"' % auth_password
+
+      if (default_realm is not None) and (len(default_realm) > 0):
+        realm = '-r %s' % default_realm
+      else:
+        realm = ''
+
+      try:
+        command = '%s %s %s -q "%s"' % (kadmin, credential, realm, query.replace('"', '\\"'))
+        return shell.checked_call(command)
+      except:
+        raise
+      finally:
+        if auth_keytab_file is not None:
+          os.remove(auth_keytab_file)
+
+  @staticmethod
+  def create_keytab_file(principal, path, auth_identity=None):
+    success = False
+
+    if (principal is not None) and (len(principal) > 0):
+      if (auth_identity is None) or (len(auth_identity) == 0):
+        norandkey = '-norandkey'
+      else:
+        norandkey = ''
+
+      if (path is not None) and (len(path) > 0):
+        keytab_file = '-k %s' % path
+      else:
+        keytab_file = ''
+
+      try:
+        result_code, output = KerberosScript.invoke_kadmin(
+          'ktadd %s %s %s' % (keytab_file, norandkey, principal),
+          auth_identity)
+
+        success = (result_code == 0)
+      except:
+        raise Fail("Failed to create keytab for principal: %s (in %s)" % (principal, path))
+
+    return success
+
+  @staticmethod
+  def create_keytab(principal, auth_identity=None):
+    keytab = None
+
+    (fd, temp_path) = tempfile.mkstemp()
+    os.remove(temp_path)
+
+    try:
+      if KerberosScript.create_keytab_file(principal, temp_path, auth_identity):
+        with open(temp_path, 'r') as f:
+          keytab = base64.b64encode(f.read())
+    finally:
+      if os.path.isfile(temp_path):
+        os.remove(temp_path)
+
+    return keytab
+
+  @staticmethod
+  def principal_exists(identity, auth_identity=None):
+    exists = False
+
+    if identity is not None:
+      principal = get_property_value(identity, 'principal')
+
+      if (principal is not None) and (len(principal) > 0):
+        try:
+          result_code, output = KerberosScript.invoke_kadmin('getprinc %s' % principal,
+                                                             auth_identity)
+          exists = (output is not None) and (("Principal: %s" % principal) in output)
+        except:
+          raise Fail("Failed to determine if principal exists: %s" % principal)
+
+    return exists
+
+  @staticmethod
+  def change_principal_password(identity, auth_identity=None):
+    success = False
+
+    if identity is not None:
+      principal = get_property_value(identity, 'principal')
+
+      if (principal is not None) and (len(principal) > 0):
+        password = get_property_value(identity, 'password')
+
+        if password is None:
+          credentials = '-randkey'
+        else:
+          credentials = '-pw "%s"' % password
+
+        try:
+          result_code, output = KerberosScript.invoke_kadmin(
+            'change_password %s %s' % (credentials, principal),
+            auth_identity)
+
+          success = (result_code == 0)
+        except:
+          raise Fail("Failed to create principal: %s" % principal)
+
+    return success
+
+  @staticmethod
+  def create_principal(identity, auth_identity=None):
+    success = False
+
+    if identity is not None:
+      principal = get_property_value(identity, 'principal')
+
+      if (principal is not None) and (len(principal) > 0):
+        password = get_property_value(identity, 'password')
+
+        if password is None:
+          credentials = '-randkey'
+        else:
+          credentials = '-pw "%s"' % password
+
+        try:
+          result_code, out = KerberosScript.invoke_kadmin(
+            'addprinc %s %s' % (credentials, principal),
+            auth_identity)
+
+          success = (result_code == 0)
+        except:
+          raise Fail("Failed to create principal: %s" % principal)
+
+    return success
+
+  @staticmethod
+  def create_principals(identities, auth_identity=None):
+    if identities is not None:
+      for identity in identities:
+        KerberosScript.create_principal(identity, auth_identity)
+
+  @staticmethod
+  def create_or_update_administrator_identity():
+    import params
+
+    if params.realm is not None:
+      admin_identity = params.get_property_value(params.realm, 'admin_identity')
+
+      if KerberosScript.principal_exists(admin_identity):
+        KerberosScript.change_principal_password(admin_identity)
+      else:
+        KerberosScript.create_principal(admin_identity)
+
+  @staticmethod
+  def test_kinit(identity):
+    principal = get_property_value(identity, 'principal')
+
+    if principal is not None:
+      keytab_file = get_property_value(identity, 'keytab_file')
+      keytab = get_property_value(identity, 'keytab')
+      password = get_property_value(identity, 'password')
+
+      # If a test keytab file is available, simply use it
+      if (keytab_file is not None) and (os.path.isfile(keytab_file)):
+        command = 'kinit -k -t %s %s' % (keytab_file, principal)
+        shell.checked_call(command)
+        return shell.checked_call('kdestroy')
+
+      # If base64-encoded test keytab data is available; then decode it, write it to a temporary file
+      # use it, and then remove the temporary file
+      elif keytab is not None:
+        (fd, test_keytab_file) = tempfile.mkstemp()
+        os.write(fd, base64.b64decode(keytab))
+        os.close(fd)
+
+        try:
+          command = 'kinit -k -t %s %s' % (test_keytab_file, principal)
+          shell.checked_call(command)
+          return shell.checked_call('kdestroy')
+        except:
+          raise
+        finally:
+          if test_keytab_file is not None:
+            os.remove(test_keytab_file)
+
+      # If no keytab data is available and a password was supplied, simply use it.
+      elif password is not None:
+        process = subprocess.Popen(['kinit', principal], stdin=subprocess.PIPE)
+        stdout, stderr = process.communicate(password)
+        if process.returncode:
+          err_msg = Logger.get_protected_text("Execution of kinit returned %d. %s" % (process.returncode, stderr))
+          raise Fail(err_msg)
+        else:
+          return shell.checked_call('kdestroy')
+      else:
+        return 0, ''
+    else:
+      return 0, ''
+
+
+  @staticmethod
+  def write_keytab_file():
+    import params
+
+    if params.keytab_details is not None:
+      data = get_property_value(params.keytab_details, 'data')
+
+      if (data is not None) and (len(data) > 0):
+        file_path = get_property_value(params.keytab_details, 'file-path')
+
+        if (file_path is not None) and (len(file_path) > 0):
+          with open(file_path, 'w') as f:
+            f.write(base64.b64decode(data))
+
+          KerberosScript._set_file_access(file_path, params.keytab_details, params.default_group)
+
+
+  @staticmethod
+  def _set_file_access(file_path, access_details, default_group=None):
+    if (file_path is not None) and os.path.isfile(file_path) and (access_details is not None):
+      import stat
+      import pwd
+      import grp
+
+      owner = get_property_value(access_details, 'owner/name')
+      owner_access = get_property_value(access_details, 'owner/access', 'rw')
+      group = get_property_value(access_details, 'group/name', default_group)
+      group_access = get_property_value(access_details, 'group/access', '')
+
+      pwnam = pwd.getpwnam(owner) if (owner is not None) and (len(owner) > 0) else None
+      uid = pwnam.pw_uid if pwnam is not None else os.geteuid()
+
+      grnam = grp.getgrnam(group) if (group is not None) and (len(group) > 0) else None
+      gid = grnam.gr_gid if grnam is not None else os.getegid()
+
+      chmod = 0
+
+      if owner_access == 'r':
+        chmod |= stat.S_IREAD
+      else:
+        chmod |= stat.S_IREAD | stat.S_IWRITE
+
+      if group_access == 'rw':
+        chmod |= stat.S_IRGRP | stat.S_IWGRP
+      elif group_access == 'r':
+        chmod |= stat.S_IRGRP
+
+      os.chmod(file_path, chmod)
+      os.chown(file_path, uid, gid)

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_server.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_server.py
new file mode 100644
index 0000000..3e15f50
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/kerberos_server.py
@@ -0,0 +1,144 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+from kerberos_common import *
+
+class KerberosServer(KerberosScript):
+  @staticmethod
+  def write_kadm5_acl():
+    import params
+
+    Directory(params.kadm5_acl_dir,
+              owner='root',
+              recursive=True,
+              group='root',
+              mode=0700
+    )
+
+    if (params.kadm5_acl_template is None) or not params.kadm5_acl_template.strip():
+      content = Template('kadm5_acl.j2')
+    else:
+      content = InlineTemplate(params.kadm5_acl_template)
+
+    File(params.kadm5_acl_path,
+         content=content,
+         owner='root',
+         group='root',
+         mode=0600
+    )
+
+  @staticmethod
+  def write_kdc_conf():
+    import params
+
+    Directory(params.kdc_conf_dir,
+              owner='root',
+              recursive=True,
+              group='root',
+              mode=0700
+    )
+
+    if (params.kdc_conf_template is None) or not params.kdc_conf_template.strip():
+      content = Template('kdc_conf.j2')
+    else:
+      content = InlineTemplate(params.kdc_conf_template)
+
+    File(params.kdc_conf_path,
+         content=content,
+         owner='root',
+         group='root',
+         mode=0600
+    )
+
+  def install(self, env):
+    import params
+
+    self.install_packages(env)
+    self.configure(env)
+
+    # Create the Kerberos database (only on install, for now)
+    Execute(
+      "%s create -s -P '%s'" % (params.kdb5_util_path, KerberosScript.create_random_password()))
+
+    # Create or update the administrator account
+    KerberosScript.create_or_update_administrator_identity()
+
+
+  def start(self, env):
+    os_family = System.get_instance().os_family
+
+    # Attempt to reconfigure the service before starting
+    self.configure(env)
+
+    # Create or update the administrator account
+    KerberosScript.create_or_update_administrator_identity()
+
+    if os_family == "suse":
+      Execute('rckadmind start')
+      Execute('rckrb5kdc start')
+    elif os_family == 'ubuntu':
+      Execute('service krb5-kdc start')
+      Execute('service krb5-admin-server start')
+    else:
+      Execute('service krb5kdc start')
+      Execute('service kadmin start')
+
+  def stop(self, env):
+    os_family = System.get_instance().os_family
+
+    if os_family == "suse":
+      Execute('rckadmind stop')
+      Execute('rckrb5kdc stop')
+    elif os_family == 'ubuntu':
+      Execute('service krb5-kdc stop')
+      Execute('service krb5-admin-server stop')
+    else:
+      Execute('service krb5kdc stop')
+      Execute('service kadmin stop')
+
+
+  def configure(self, env):
+    import params
+    env.set_params(params)
+
+    KerberosServer.write_krb5_conf()
+    KerberosServer.write_kdc_conf()
+    KerberosServer.write_kadm5_acl()
+
+  def status(self, env):
+    import params
+
+    if params.os_family == "suse":
+      try:
+        Execute('checkproc `which krb5kdc`')
+        Execute('checkproc `which kadmind`')
+      except Fail as ex:
+        raise ComponentIsNotRunning()
+
+    elif params.os_family == 'ubuntu':
+      check_process_status(params.kdamin_pid_path)
+      check_process_status(params.krb5kdc_pid_path)
+
+    else:
+      check_process_status(params.kdamin_pid_path)
+      check_process_status(params.krb5kdc_pid_path)
+
+
+if __name__ == "__main__":
+  KerberosServer().execute()

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/params.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/params.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/params.py
new file mode 100644
index 0000000..664de5b
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/params.py
@@ -0,0 +1,197 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+from resource_management import *
+from utils import get_property_value, get_unstructured_data
+
+os_family = System.get_instance().os_family
+
+krb5_conf_dir = '/etc'
+krb5_conf_file = 'krb5.conf'
+krb5_conf_path = krb5_conf_dir + '/' + krb5_conf_file
+
+if os_family == 'suse':
+  kdc_conf_dir = '/var/lib/kerberos/krb5kdc'
+elif os_family == 'ubuntu':
+  kdc_conf_dir = '/etc/krb5kdc'
+else:
+  kdc_conf_dir = '/var/kerberos/krb5kdc'
+kdc_conf_file = 'kdc.conf'
+kdc_conf_path = kdc_conf_dir + '/' + kdc_conf_file
+
+kadm5_acl_dir = kdc_conf_dir  # Typically kadm5.acl and kdc.conf exist in the same directory
+kadm5_acl_file = 'kadm5.acl'
+kadm5_acl_path = kadm5_acl_dir + '/' + kadm5_acl_file
+
+config = Script.get_config()
+
+command_params = None
+configurations = None
+keytab_details = None
+default_group = None
+cluster_env = None
+kdc_server_host = None
+cluster_host_info = None
+
+kdb5_util_path = 'kdb5_util'
+
+kdamin_pid_path = '/var/run/kadmind.pid'
+krb5kdc_pid_path = '/var/run/krb5kdc.pid'
+
+smoke_test_principal = None
+smoke_test_keytab_file = None
+
+# If a test keytab file is available, simply use it
+
+
+if config is not None:
+  command_params = get_property_value(config, 'commandParams')
+  if command_params is not None:
+    keytab_details = get_unstructured_data(command_params, 'keytab')
+
+  configurations = get_property_value(config, 'configurations')
+  if configurations is not None:
+    cluster_env = get_property_value(configurations, 'cluster-env')
+
+    if cluster_env is not None:
+      smoke_test_principal = get_property_value(cluster_env, 'smokeuser')
+      smoke_test_keytab_file = get_property_value(cluster_env, 'smokeuser_keytab')
+
+      default_group = get_property_value(cluster_env, 'user_group')
+
+      if default_group is None:
+        default_group = get_property_value(cluster_env, 'user-group')
+
+  cluster_host_info = get_property_value(config, 'clusterHostInfo')
+  if cluster_host_info is not None:
+    kdc_server_hosts = get_property_value(cluster_host_info, 'kdc_server_hosts')
+
+    if (kdc_server_hosts is not None) and (len(kdc_server_hosts) > 0):
+      kdc_server_host = kdc_server_hosts[0]
+
+  # ################################################################################################
+  # Get krb5.conf template data
+  # ################################################################################################
+  logging_default = 'FILE:/var/log/krb5libs.log'
+  logging_kdc = 'FILE:/var/log/krb5kdc.log'
+  logging_admin_server = 'FILE:/var/log/kadmind.log'
+  libdefaults_dns_lookup_realm = 'false'
+  libdefaults_dns_lookup_kdc = 'false'
+  libdefaults_ticket_lifetime = '24h'
+  libdefaults_renew_lifetime = '7d'
+  libdefaults_forwardable = 'true'
+  libdefaults_default_tgs_enctypes = 'aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 ' \
+                                     'arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac ' \
+                                     'des-cbc-crc des-cbc-md5 des-cbc-md4'
+  libdefaults_default_tkt_enctypes = 'aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 ' \
+                                     'arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac ' \
+                                     'des-cbc-crc des-cbc-md5 des-cbc-md4'
+  realm = 'EXAMPLE.COM'
+  domains = ''
+  kdc_host = 'localhost'
+  admin_server_host = None
+  admin_principal = None
+  admin_password = None
+  admin_keytab = None
+  test_principal = None
+  test_password = None
+  test_keytab = None
+  test_keytab_file = None
+
+  krb5_conf_template = None
+
+  krb5_conf_data = get_property_value(configurations, 'krb5-conf')
+
+  if krb5_conf_data is not None:
+    logging_default = get_property_value(krb5_conf_data, 'logging_default', logging_default)
+    logging_kdc = get_property_value(krb5_conf_data, 'logging_kdc', logging_kdc)
+    logging_admin_server = get_property_value(krb5_conf_data, 'logging_admin_server',
+                                              logging_admin_server)
+    libdefaults_dns_lookup_realm = get_property_value(krb5_conf_data,
+                                                      'libdefaults_dns_lookup_realm',
+                                                      libdefaults_dns_lookup_realm)
+    libdefaults_dns_lookup_kdc = get_property_value(krb5_conf_data, 'libdefaults_dns_lookup_kdc',
+                                                    libdefaults_dns_lookup_kdc)
+    libdefaults_ticket_lifetime = get_property_value(krb5_conf_data, 'libdefaults_ticket_lifetime',
+                                                     libdefaults_ticket_lifetime)
+    libdefaults_renew_lifetime = get_property_value(krb5_conf_data, 'libdefaults_renew_lifetime',
+                                                    libdefaults_renew_lifetime)
+    libdefaults_forwardable = get_property_value(krb5_conf_data, 'libdefaults_forwardable',
+                                                 libdefaults_forwardable)
+    libdefaults_default_tgs_enctypes = get_property_value(krb5_conf_data,
+                                                          'libdefaults_default_tgs_enctypes',
+                                                          libdefaults_default_tgs_enctypes)
+    libdefaults_default_tkt_enctypes = get_property_value(krb5_conf_data,
+                                                          'libdefaults_default_tkt_enctypes',
+                                                          libdefaults_default_tkt_enctypes)
+    realm = get_property_value(krb5_conf_data, 'realm', realm)
+    domains = get_property_value(krb5_conf_data, 'domains', domains)
+    kdc_host = get_property_value(krb5_conf_data, 'kdc_host', kdc_host)
+    admin_server_host = get_property_value(krb5_conf_data, 'admin_server_host', admin_server_host)
+
+    admin_principal = get_property_value(krb5_conf_data, 'admin_principal', admin_principal)
+    admin_password = get_property_value(krb5_conf_data, 'admin_password', admin_password)
+    admin_keytab = get_property_value(krb5_conf_data, 'admin_keytab', admin_keytab)
+
+    test_principal = get_property_value(krb5_conf_data, 'test_principal', test_principal)
+    test_password = get_property_value(krb5_conf_data, 'test_password', test_password)
+    test_keytab = get_property_value(krb5_conf_data, 'test_keytab', test_keytab)
+    test_keytab_file = get_property_value(krb5_conf_data, 'test_keytab_file', test_keytab_file)
+
+    krb5_conf_template = get_property_value(krb5_conf_data, 'content', krb5_conf_template)
+    krb5_conf_dir = get_property_value(krb5_conf_data, 'conf_dir', krb5_conf_dir)
+    krb5_conf_file = get_property_value(krb5_conf_data, 'conf_file', krb5_conf_file)
+    krb5_conf_path = krb5_conf_dir + '/' + krb5_conf_file
+
+  # ################################################################################################
+  # Get kdc.conf template data
+  # ################################################################################################
+  kdcdefaults_kdc_ports = "88"
+  kdcdefaults_kdc_tcp_ports = "88"
+
+  kdc_conf_template = None
+
+  kdc_conf_data = get_property_value(configurations, 'kdc-conf')
+
+  if kdc_conf_data is not None:
+    kdcdefaults_kdc_ports = get_property_value(kdc_conf_data, 'kdcdefaults_kdc_ports',
+                                               kdcdefaults_kdc_ports)
+    kdcdefaults_kdc_tcp_ports = get_property_value(kdc_conf_data, 'kdcdefaults_kdc_tcp_ports',
+                                                   kdcdefaults_kdc_tcp_ports)
+
+    kdc_conf_template = get_property_value(kdc_conf_data, 'content', kdc_conf_template)
+    kdc_conf_dir = get_property_value(kdc_conf_data, 'conf_dir', kdc_conf_dir)
+    kdc_conf_file = get_property_value(kdc_conf_data, 'conf_file', kdc_conf_file)
+    kdc_conf_path = kdc_conf_dir + '/' + kdc_conf_file
+
+  # ################################################################################################
+  # Get kadm5.acl template data
+  # ################################################################################################
+  kdcdefaults_kdc_ports = '88'
+  kdcdefaults_kdc_tcp_ports = '88'
+
+  kadm5_acl_template = None
+
+  kadm5_acl_data = get_property_value(configurations, 'kadm5-acl')
+
+  if kadm5_acl_data is not None:
+    kadm5_acl_template = get_property_value(kadm5_acl_data, 'content', kadm5_acl_template)
+    kadm5_acl_dir = get_property_value(kadm5_acl_data, 'conf_dir', kadm5_acl_dir)
+    kadm5_acl_file = get_property_value(kadm5_acl_data, 'conf_file', kadm5_acl_file)
+    kadm5_acl_path = kadm5_acl_dir + '/' + kadm5_acl_file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/service_check.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/service_check.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/service_check.py
new file mode 100644
index 0000000..73b9c7a
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/service_check.py
@@ -0,0 +1,63 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+Ambari Agent
+
+"""
+
+from kerberos_common import *
+from resource_management import *
+
+class KerberosServiceCheck(KerberosScript):
+  def service_check(self, env):
+    import params
+
+    # First attempt to test using the smoke test user, if data is available
+    if ((params.smoke_test_principal is not None) and
+          (params.smoke_test_keytab_file is not None) and
+          os.path.isfile(params.smoke_test_keytab_file)):
+      print "Performing kinit using smoke test user: %s" % params.smoke_test_principal
+      code, out = self.test_kinit({
+        'principal': params.smoke_test_principal,
+        'keytab_file': params.smoke_test_keytab_file
+      })
+      test_performed = True
+
+    # Else if a test credentials is specified, try to test using that
+    elif params.test_principal is not None:
+      print "Performing kinit using test user: %s" % params.test_principal
+      code, out = self.test_kinit({
+        'principal': params.test_principal,
+        'keytab_file': params.test_keytab_file,
+        'keytab': params.test_keytab,
+        'password': params.test_password
+      })
+      test_performed = True
+
+    else:
+      code = 0
+      out = ''
+      test_performed = False
+
+    if test_performed:
+      if code == 0:
+        print "Test executed successfully."
+      else:
+        print "Test failed with error code %d: %s." % (code, out)
+
+if __name__ == "__main__":
+  KerberosServiceCheck().execute()

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/utils.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/utils.py b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/utils.py
new file mode 100644
index 0000000..79e89e6
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/scripts/utils.py
@@ -0,0 +1,69 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+def get_property_value(dictionary, property_name, null_value=None):
+  return dictionary[property_name] if property_name in dictionary else null_value
+
+def get_unstructured_data(dictionary, property_name):
+  prefix = property_name + '/'
+  prefix_len = len(prefix)
+  return dict((k[prefix_len:], v) for k, v in dictionary.iteritems() if k.startswith(prefix))
+
+def split_host_and_port(host):
+  """
+  Splits a string into its host and port components
+
+  :param host: a string matching the following patern: <host name | ip address>[:port]
+  :return: a Dictionary containing 'host' and 'port' entries for the input value
+  """
+
+  if host is None:
+    host_and_port = None
+  else:
+    host_and_port = {}
+    parts = host.split(":")
+
+    if parts is not None:
+      length = len(parts)
+
+      if length > 0:
+        host_and_port['host'] = parts[0]
+
+        if length > 1:
+          host_and_port['port'] = int(parts[1])
+
+  return host_and_port
+
+def set_port(host, port):
+  """
+  Sets the port for a host specification, potentially replacing an existing port declaration
+
+  :param host: a string matching the following pattern: <host name | ip address>[:port]
+  :param port: a string or integer declaring the (new) port
+  :return: a string declaring the new host/port specification
+  """
+  if port is None:
+    return host
+  else:
+    host_and_port = split_host_and_port(host)
+
+    if (host_and_port is not None) and ('host' in host_and_port):
+      return "%s:%s" % (host_and_port['host'], port)
+    else:
+      return host

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kadm5_acl.j2
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kadm5_acl.j2 b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kadm5_acl.j2
new file mode 100644
index 0000000..d82ae23
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kadm5_acl.j2
@@ -0,0 +1,20 @@
+{#
+# 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
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#}
+*/admin@{{realm}}	*
+
+{# Append additional realm declarations should be placed below #}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kdc_conf.j2
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kdc_conf.j2 b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kdc_conf.j2
new file mode 100644
index 0000000..c067bae
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/kdc_conf.j2
@@ -0,0 +1,30 @@
+{#
+# 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
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#}
+[kdcdefaults]
+  kdc_ports = {{kdcdefaults_kdc_ports}}
+  kdc_tcp_ports = {{kdcdefaults_kdc_tcp_ports}}
+
+[realms]
+  {{realm}} = {
+    acl_file = {{kadm5_acl_path}}
+    dict_file = /usr/share/dict/words
+    admin_keytab = {{kadm5_acl_dir}}/kadm5.keytab
+    supported_enctypes = {{libdefaults_default_tgs_enctypes}}
+  }
+
+{# Append additional realm declarations should be placed below #}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/krb5_conf.j2
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/krb5_conf.j2 b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/krb5_conf.j2
new file mode 100644
index 0000000..41628b9
--- /dev/null
+++ b/ambari-server/src/main/resources/stacks/HDP/2.2/services/KERBEROS/package/templates/krb5_conf.j2
@@ -0,0 +1,47 @@
+{#
+# 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
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#}
+[libdefaults]
+  renew_lifetime = {{libdefaults_renew_lifetime}}
+  forwardable = {{libdefaults_forwardable}}
+  default_realm = {{realm|upper()}}
+  ticket_lifetime = {{libdefaults_ticket_lifetime}}
+  dns_lookup_realm = {{libdefaults_dns_lookup_realm}}
+  dns_lookup_kdc = {{libdefaults_dns_lookup_kdc}}
+
+{% if domains %}
+[domain_realm]
+{% for domain in domains %}
+  {{domain}} = {{realm|upper()}}
+{% endfor %}
+{% endif %}
+
+[logging]
+  default = {{logging_default}}
+{#
+# The following options are unused unless a managed KDC is installed
+  admin_server = {{logging_admin_server}}
+  kdc = {{logging_admin_kdc}}
+#}
+
+[realms]
+  {{realm}} = {
+    admin_server = {{admin_server_host|default(kdc_host, True)}}
+    kdc = {{kdc_host}}
+  }
+
+{# Append additional realm declarations should be placed below #}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java
new file mode 100644
index 0000000..f3ef748
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/KerberosServiceMetaInfoTest.java
@@ -0,0 +1,283 @@
+/*
+ * 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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.api.services;
+
+import junit.framework.Assert;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.metadata.ActionMetadata;
+import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
+import org.apache.ambari.server.orm.dao.MetainfoDAO;
+import org.apache.ambari.server.stack.StackManager;
+import org.apache.ambari.server.state.AutoDeployInfo;
+import org.apache.ambari.server.state.ComponentInfo;
+import org.apache.ambari.server.state.DependencyInfo;
+import org.apache.ambari.server.state.ServiceInfo;
+import org.apache.ambari.server.state.alert.AlertDefinitionFactory;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.*;
+
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.fail;
+
+public class KerberosServiceMetaInfoTest {
+  private final static Logger LOG = LoggerFactory.getLogger(KerberosServiceMetaInfoTest.class);
+  private ServiceInfo serviceInfo = null;
+
+  /* ********************************************************************************************
+   * In the event we want to create a superclass that can be used to execute tests on service
+   * metainfo data, the following methods may be useful
+   * ******************************************************************************************** */
+  private void testAutoDeploy(Map<String, AutoDeployInfo> expectedAutoDeployMap) throws AmbariException {
+    Assert.assertNotNull(serviceInfo);
+
+    List<ComponentInfo> componentList = serviceInfo.getComponents();
+
+    Assert.assertNotNull(componentList);
+    Assert.assertEquals(expectedAutoDeployMap.size(), componentList.size());
+
+    for (ComponentInfo component : componentList) {
+      Assert.assertTrue(expectedAutoDeployMap.containsKey(component.getName()));
+
+      AutoDeployInfo expectedAutoDeploy = expectedAutoDeployMap.get(component.getName());
+      AutoDeployInfo componentAutoDeploy = component.getAutoDeploy();
+
+      if (expectedAutoDeploy == null)
+        Assert.assertNull(componentAutoDeploy);
+      else {
+        Assert.assertNotNull(componentAutoDeploy);
+        Assert.assertEquals(expectedAutoDeploy.isEnabled(), componentAutoDeploy.isEnabled());
+        Assert.assertEquals(expectedAutoDeploy.getCoLocate(), componentAutoDeploy.getCoLocate());
+      }
+    }
+  }
+
+  private void testCardinality(HashMap<String, String> expectedCardinalityMap) throws AmbariException {
+    Assert.assertNotNull(serviceInfo);
+
+    List<ComponentInfo> componentList = serviceInfo.getComponents();
+
+    Assert.assertNotNull(componentList);
+    Assert.assertEquals(expectedCardinalityMap.size(), componentList.size());
+
+    for (ComponentInfo component : componentList) {
+      Assert.assertTrue(expectedCardinalityMap.containsKey(component.getName()));
+      Assert.assertEquals(expectedCardinalityMap.get(component.getName()), component.getCardinality());
+    }
+  }
+
+  protected void testDependencies(Map<String, Map<String, DependencyInfo>> expectedDependenciesMap) throws AmbariException {
+    Assert.assertNotNull(serviceInfo);
+
+    List<ComponentInfo> componentList = serviceInfo.getComponents();
+
+    Assert.assertNotNull(componentList);
+    Assert.assertEquals(expectedDependenciesMap.size(), componentList.size());
+
+    for (ComponentInfo component : componentList) {
+      Assert.assertTrue(expectedDependenciesMap.containsKey(component.getName()));
+
+      Map<String, ? extends DependencyInfo> expectedDependencyMap = expectedDependenciesMap.get(component.getName());
+      List<DependencyInfo> componentDependencies = component.getDependencies();
+
+      if (expectedDependencyMap == null)
+        Assert.assertNull(componentDependencies);
+      else {
+        Assert.assertEquals(expectedDependencyMap.size(), componentDependencies.size());
+
+        for (DependencyInfo componentDependency : componentDependencies) {
+          DependencyInfo expectedDependency = expectedDependencyMap.get(componentDependency.getComponentName());
+
+          Assert.assertNotNull(expectedDependency);
+
+          AutoDeployInfo expectedDependencyAutoDeploy = expectedDependency.getAutoDeploy();
+          AutoDeployInfo componentDependencyAutoDeploy = componentDependency.getAutoDeploy();
+
+          Assert.assertEquals(expectedDependency.getName(), componentDependency.getName());
+          Assert.assertEquals(expectedDependency.getServiceName(), componentDependency.getServiceName());
+          Assert.assertEquals(expectedDependency.getComponentName(), componentDependency.getComponentName());
+          Assert.assertEquals(expectedDependency.getScope(), componentDependency.getScope());
+
+          if (expectedDependencyAutoDeploy == null)
+            Assert.assertNull(componentDependencyAutoDeploy);
+          else {
+            Assert.assertNotNull(componentDependencyAutoDeploy);
+            Assert.assertEquals(expectedDependencyAutoDeploy.isEnabled(), componentDependencyAutoDeploy.isEnabled());
+            Assert.assertEquals(expectedDependencyAutoDeploy.getCoLocate(), componentDependencyAutoDeploy.getCoLocate());
+          }
+        }
+      }
+    }
+  }
+
+  @Before
+  public void before() throws Exception {
+    File stackRoot = new File("src/main/resources/stacks");
+    LOG.info("Stacks file " + stackRoot.getAbsolutePath());
+
+    AmbariMetaInfo metaInfo = createAmbariMetaInfo(stackRoot, new File("target/version"), true);
+    metaInfo.init();
+
+    serviceInfo = metaInfo.getService("HDP", "2.2", "KERBEROS");
+  }
+  /* ******************************************************************************************* */
+
+  @Test
+  public void test220Cardinality() throws Exception {
+    testCardinality(new HashMap<String, String>() {
+      {
+        put("KDC_SERVER", "0-1");
+        put("KERBEROS_CLIENT", "ALL");
+      }
+    });
+  }
+
+  @Test
+  public void test220AutoDeploy() throws Exception {
+    testAutoDeploy(new HashMap<String, AutoDeployInfo>() {
+      {
+        put("KDC_SERVER", null);
+        put("KERBEROS_CLIENT", new AutoDeployInfo() {{
+          setEnabled(true);
+          setCoLocate(null);
+        }});
+      }
+    });
+  }
+
+  @Test
+  public void test220Dependencies() throws Exception {
+    testDependencies(new HashMap<String, Map<String, DependencyInfo>>() {
+      {
+        put("KDC_SERVER", new HashMap<String, DependencyInfo>() {{
+              put("KERBEROS_CLIENT",
+                  new DependencyInfo() {{
+                    setName("KERBEROS/KERBEROS_CLIENT");
+                    setAutoDeploy(new AutoDeployInfo() {{
+                      setEnabled(true);
+                      setCoLocate(null);
+                    }});
+                    setScope("cluster");
+                  }});
+            }}
+        );
+
+        put("KERBEROS_CLIENT", new HashMap<String, DependencyInfo>());
+      }
+    });
+  }
+
+  private TestAmbariMetaInfo createAmbariMetaInfo(File stackRoot, File versionFile, boolean replayMocks) throws Exception {
+    TestAmbariMetaInfo metaInfo = new TestAmbariMetaInfo(stackRoot, versionFile);
+    if (replayMocks) {
+      metaInfo.replayAllMocks();
+
+      try {
+        metaInfo.init();
+      } catch(Exception e) {
+        LOG.info("Error in initializing ", e);
+        throw e;
+      }
+      waitForAllReposToBeResolved(metaInfo);
+    }
+
+    return metaInfo;
+  }
+
+  private void waitForAllReposToBeResolved(AmbariMetaInfo metaInfo) throws Exception {
+    int maxWait = 45000;
+    int waitTime = 0;
+    StackManager sm = metaInfo.getStackManager();
+    while (waitTime < maxWait && ! sm.haveAllRepoUrlsBeenResolved()) {
+      Thread.sleep(5);
+      waitTime += 5;
+    }
+
+    if (waitTime >= maxWait) {
+      fail("Latest Repo tasks did not complete");
+    }
+  }
+
+  private static class TestAmbariMetaInfo extends AmbariMetaInfo {
+
+    MetainfoDAO metaInfoDAO;
+    AlertDefinitionDAO alertDefinitionDAO;
+    AlertDefinitionFactory alertDefinitionFactory;
+    OsFamily osFamily;
+
+    public TestAmbariMetaInfo(File stackRoot, File serverVersionFile) throws Exception {
+      super(stackRoot, serverVersionFile);
+      // MetainfoDAO
+      metaInfoDAO = createNiceMock(MetainfoDAO.class);
+      Class<?> c = getClass().getSuperclass();
+      Field f = c.getDeclaredField("metaInfoDAO");
+      f.setAccessible(true);
+      f.set(this, metaInfoDAO);
+
+      // ActionMetadata
+      ActionMetadata actionMetadata = new ActionMetadata();
+      f = c.getDeclaredField("actionMetadata");
+      f.setAccessible(true);
+      f.set(this, actionMetadata);
+
+      //AlertDefinitionDAO
+      alertDefinitionDAO = createNiceMock(AlertDefinitionDAO.class);
+      f = c.getDeclaredField("alertDefinitionDao");
+      f.setAccessible(true);
+      f.set(this, alertDefinitionDAO);
+
+      //AlertDefinitionFactory
+      //alertDefinitionFactory = createNiceMock(AlertDefinitionFactory.class);
+      alertDefinitionFactory = new AlertDefinitionFactory();
+      f = c.getDeclaredField("alertDefinitionFactory");
+      f.setAccessible(true);
+      f.set(this, alertDefinitionFactory);
+
+      //AmbariEventPublisher
+      AmbariEventPublisher ambariEventPublisher = new AmbariEventPublisher();
+      f = c.getDeclaredField("eventPublisher");
+      f.setAccessible(true);
+      f.set(this, ambariEventPublisher);
+
+      //OSFamily
+      Configuration config = createNiceMock(Configuration.class);
+      expect(config.getSharedResourcesDirPath()).andReturn("./src/test/resources").anyTimes();
+      replay(config);
+      osFamily = new OsFamily(config);
+      f = c.getDeclaredField("os_family");
+      f.setAccessible(true);
+      f.set(this, osFamily);
+    }
+
+    public void replayAllMocks() {
+      replay(metaInfoDAO, alertDefinitionDAO);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py
new file mode 100644
index 0000000..95c357d
--- /dev/null
+++ b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py
@@ -0,0 +1,117 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+import os
+import use_cases
+
+from stacks.utils.RMFTestCase import *
+
+class TestKerberosClient(RMFTestCase):
+  def test_configure_managed_kdc(self):
+    json_data = use_cases.get_manged_kdc_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_client.py",
+                       classname="KerberosClient",
+                       command="configure",
+                       config_dict=json_data)
+
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=Template('krb5_conf.j2'),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+  def test_configure_unmanaged_kdc(self):
+    json_data = use_cases.get_unmanged_kdc_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_client.py",
+                       classname="KerberosClient",
+                       command="configure",
+                       config_dict=json_data)
+
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+  def test_configure_unmanaged_ad(self):
+    json_data = use_cases.get_unmanged_ad_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_client.py",
+                       classname="KerberosClient",
+                       command="configure",
+                       config_dict=json_data)
+
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+  def test_configure_cross_realm_trust(self):
+    json_data = use_cases.get_cross_realm_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_client.py",
+                       classname="KerberosClient",
+                       command="configure",
+                       config_dict=json_data)
+
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/6fbfdb4a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_server.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_server.py b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_server.py
new file mode 100644
index 0000000..8629861
--- /dev/null
+++ b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_server.py
@@ -0,0 +1,248 @@
+"""
+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
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+import os
+import use_cases
+
+from stacks.utils.RMFTestCase import *
+
+class TestKerberosServer(RMFTestCase):
+  def test_configure_managed_kdc(self):
+    json_data = use_cases.get_manged_kdc_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_server.py",
+                       classname="KerberosServer",
+                       command="configure",
+                       config_dict=json_data)
+
+    # Validate krb5.conf file
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=Template('krb5_conf.j2'),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+    # Validate kdc.conf file
+    self.assertResourceCalled('Directory', use_cases.get_kdc_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kdc_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_kdc_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=Template('kdc_conf.j2'),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+    # Validate kadm5.acl file
+    self.assertResourceCalled('Directory', use_cases.get_kadm5_acl_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kadm5_acl_dir(json_data) +
+                 "/" +
+                 use_cases.get_kadm5_acl_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=Template('kadm5_acl.j2'),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+  def test_configure_unmanaged_kdc(self):
+    json_data = use_cases.get_unmanged_kdc_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_server.py",
+                       classname="KerberosServer",
+                       command="configure",
+                       config_dict=json_data)
+
+    # Validate krb5.conf file
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+    # Validate kdc.conf file
+    self.assertResourceCalled('Directory', use_cases.get_kdc_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kdc_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_kdc_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kdc_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+    # Validate kadm5.acl file
+    self.assertResourceCalled('Directory', use_cases.get_kadm5_acl_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kadm5_acl_dir(json_data) +
+                 "/" +
+                 use_cases.get_kadm5_acl_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kadm5_acl_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+  def test_configure_unmanaged_ad(self):
+    json_data = use_cases.get_unmanged_ad_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_server.py",
+                       classname="KerberosServer",
+                       command="configure",
+                       config_dict=json_data)
+
+    # Validate krb5.conf file
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+    # Validate kdc.conf file
+    self.assertResourceCalled('Directory', use_cases.get_kdc_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kdc_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_kdc_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kdc_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+    # Validate kadm5.acl file
+    self.assertResourceCalled('Directory', use_cases.get_kadm5_acl_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kadm5_acl_dir(json_data) +
+                 "/" +
+                 use_cases.get_kadm5_acl_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kadm5_acl_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+  def test_configure_cross_realm_trust(self):
+    json_data = use_cases.get_cross_realm_use_case()
+
+    self.executeScript("2.2/services/KERBEROS/package/scripts/kerberos_server.py",
+                       classname="KerberosServer",
+                       command="configure",
+                       config_dict=json_data)
+
+    # Validate krb5.conf file
+    self.assertResourceCalled('Directory', use_cases.get_krb5_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0755,
+                              recursive=True)
+
+    file_path = (use_cases.get_krb5_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_krb5_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_krb5_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0644)
+
+    # Validate kdc.conf file
+    self.assertResourceCalled('Directory', use_cases.get_kdc_conf_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kdc_conf_dir(json_data) +
+                 "/" +
+                 use_cases.get_kdc_conf_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kdc_conf_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
+
+    # Validate kadm5.acl file
+    self.assertResourceCalled('Directory', use_cases.get_kadm5_acl_dir(json_data),
+                              owner='root',
+                              group='root',
+                              mode=0700,
+                              recursive=True)
+
+    file_path = (use_cases.get_kadm5_acl_dir(json_data) +
+                 "/" +
+                 use_cases.get_kadm5_acl_file(json_data))
+    self.assertResourceCalled('File', file_path,
+                              content=InlineTemplate(use_cases.get_kadm5_acl_template(json_data)),
+                              owner='root',
+                              group='root',
+                              mode=0600)
\ No newline at end of file