Hello community,

here is the log from the commit of package crmsh for openSUSE:Factory checked 
in at 2018-10-04 19:00:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crmsh (Old)
 and      /work/SRC/openSUSE:Factory/.crmsh.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crmsh"

Thu Oct  4 19:00:58 2018 rev:150 rq:639615 version:4.0.0+git.1538492109.4b1170b0

Changes:
--------
--- /work/SRC/openSUSE:Factory/crmsh/crmsh.changes      2018-09-28 
08:53:13.937743671 +0200
+++ /work/SRC/openSUSE:Factory/.crmsh.new/crmsh.changes 2018-10-04 
19:01:02.559231794 +0200
@@ -1,0 +2,9 @@
+Tue Oct 02 14:55:31 UTC 2018 - kgronl...@suse.com
+
+- Update to version 4.0.0+git.1538492109.4b1170b0:
+  * medium: bootstrap: Correctly check rrp_mode flag (bsc#1110463)
+  * medium: bootstrap: Pick first match for multiple routes (bsc#1106946)
+  * medium: utils: Use cloud metadata service to discover IP (bsc#1106946)
+  * Fix: bootstrap: change default ip address way for both mcast and 
unicat(bsc#1109975,bsc#1109974)
+
+-------------------------------------------------------------------

Old:
----
  crmsh-4.0.0+git.1537967262.68a0bd1e.tar.bz2

New:
----
  crmsh-4.0.0+git.1538492109.4b1170b0.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crmsh.spec ++++++
--- /var/tmp/diff_new_pack.4stBX7/_old  2018-10-04 19:01:03.075231253 +0200
+++ /var/tmp/diff_new_pack.4stBX7/_new  2018-10-04 19:01:03.075231253 +0200
@@ -36,7 +36,7 @@
 Summary:        High Availability cluster command-line interface
 License:        GPL-2.0-or-later
 Group:          %{pkg_group}
-Version:        4.0.0+git.1537967262.68a0bd1e
+Version:        4.0.0+git.1538492109.4b1170b0
 Release:        0
 Url:            http://crmsh.github.io
 Source0:        %{name}-%{version}.tar.bz2

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.4stBX7/_old  2018-10-04 19:01:03.103231224 +0200
+++ /var/tmp/diff_new_pack.4stBX7/_new  2018-10-04 19:01:03.107231220 +0200
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
             <param name="url">git://github.com/ClusterLabs/crmsh.git</param>
-          <param 
name="changesrevision">8ea00b67525414e1682ba1eced82b93281692904</param></service></servicedata>
\ No newline at end of file
+          <param 
name="changesrevision">16b0d4178d68d1f61377f4db12a53617d21f6e84</param></service></servicedata>
\ No newline at end of file

++++++ crmsh-4.0.0+git.1537967262.68a0bd1e.tar.bz2 -> 
crmsh-4.0.0+git.1538492109.4b1170b0.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/crmsh-4.0.0+git.1537967262.68a0bd1e/crmsh/bootstrap.py 
new/crmsh-4.0.0+git.1538492109.4b1170b0/crmsh/bootstrap.py
--- old/crmsh-4.0.0+git.1537967262.68a0bd1e/crmsh/bootstrap.py  2018-09-26 
15:07:42.000000000 +0200
+++ new/crmsh-4.0.0+git.1538492109.4b1170b0/crmsh/bootstrap.py  2018-10-02 
16:55:09.000000000 +0200
@@ -235,6 +235,21 @@
     status_done()
 
 
+def pick_default_value(default_list, prev_list):
+    """
+    Provide default value for function 'prompt_for_string'.
+    Make sure give different default value in multi-ring mode.
+
+    Parameters:
+    * default_list - default value list for config item
+    * prev_list    - previous value for config item in multi-ring mode
+    """
+    for value in default_list:
+        if value not in prev_list:
+            return value
+    return ""
+
+
 def start_service(service):
     """
     Start and enable systemd service
@@ -886,11 +901,6 @@
 
 
 def init_corosync_unicast():
-    def pick_default_value(vlist, ilist):
-        # give a different value for second config items
-        if len(ilist) == 1:
-            vlist.remove(ilist[0])
-        return vlist[0]
 
     if _context.yes_to_all:
         status("Configuring corosync (unicast)")
@@ -911,27 +921,18 @@
     mcastport_res = []
     default_ports = ["5405", "5407"]
     two_rings = False
-    default_networks = []
 
-    if _context.ipv6:
-        network_list = []
-        all_ = utils.network_v6_all()
-        for item in all_.values():
-            network_list.extend(item)
-        default_networks = [utils.get_ipv6_network(x) for x in network_list]
-    else:
-        network_list = utils.network_all()
-        if len(network_list) > 1:
-            default_networks = [_context.ip_network, 
network_list.remove(_context.ip_network)]
-        else:
-            default_networks = [_context.ip_network]
-    if not default_networks:
+    local_iplist = utils.ip_in_local(_context.ipv6)
+    len_iplist = len(local_iplist)
+    if len_iplist == 0:
         error("No network configured at {}!".format(utils.this_node()))
 
+    default_ip = [_context.ip_address] + [ip for ip in local_iplist if ip != 
_context.ip_address]
+
     for i in 0, 1:
         ringXaddr = prompt_for_string('Address for ring{}'.format(i),
                                       r'([0-9]+\.){3}[0-9]+|[0-9a-fA-F]{1,4}:',
-                                      _context.ip_address if i == 0 and 
_context.ip_address else "",
+                                      pick_default_value(default_ip, 
ringXaddr_res),
                                       valid_ucastIP,
                                       ringXaddr_res)
         if not ringXaddr:
@@ -948,7 +949,7 @@
         mcastport_res.append(mcastport)
 
         if i == 1 or \
-           len(default_networks) == 1 or \
+           len_iplist == 1 or \
            not _context.second_hb or \
            not confirm("\nAdd another heartbeat line?"):
             break
@@ -976,12 +977,6 @@
             random.randint(0, 255),
             random.randint(1, 255))
 
-    def pick_default_value(vlist, ilist):
-        # give a different value for second config items
-        if len(ilist) == 1:
-            vlist.remove(ilist[0])
-        return vlist[0]
-
     if _context.yes_to_all:
         status("Configuring corosync")
     else:
@@ -1013,7 +1008,8 @@
     else:
         network_list = utils.network_all()
         if len(network_list) > 1:
-            default_networks = [_context.ip_network, 
network_list.remove(_context.ip_network)]
+            network_list.remove(_context.ip_network)
+            default_networks = [_context.ip_network, network_list[0]]
         else:
             default_networks = [_context.ip_network]
     if not default_networks:
@@ -1094,15 +1090,14 @@
     """
     Configure corosync (unicast or multicast, encrypted?)
     """
-    @utils.memoize
-    def check_amazon():
-        if not utils.is_program("dmidecode"):
-            return False
-        _rc, outp = utils.get_stdout("dmidecode -s system-version")
-        return re.search(r"\<.*\.amazon\>", outp) is not None
+    def requires_unicast():
+        host = utils.detect_cloud()
+        if host is not None:
+            status("Detected cloud platform: {}".format(host))
+        return host is not None
 
     init_corosync_auth()
-    if _context.unicast or check_amazon():
+    if _context.unicast or requires_unicast():
         init_corosync_unicast()
     else:
         init_corosync_multicast()
@@ -1676,7 +1671,7 @@
     # check whether have two rings
     rrp_flag = False
     rrp = corosync.get_value("totem.rrp_mode")
-    if rrp:
+    if rrp in ('active', 'passive'):
         rrp_flag = True
 
     # Need to do this if second (or subsequent) node happens to be up and
@@ -1712,12 +1707,19 @@
     # if unicast, we need to add our node to $corosync.conf()
     is_unicast = "nodelist" in open(corosync.conf()).read()
     if is_unicast:
+        local_iplist = utils.ip_in_local(_context.ipv6)
+        len_iplist = len(local_iplist)
+        if len_iplist == 0:
+            error("No network configured at {}!".format(utils.this_node()))
+
+        default_ip = [_context.ip_address] + [ip for ip in local_iplist if ip 
!= _context.ip_address]
+
         ringXaddr_res = []
         for i in 0, 1:
             while True:
                 ringXaddr = prompt_for_string('Address for ring{}'.format(i),
                                               
r'([0-9]+\.){3}[0-9]+|[0-9a-fA-F]{1,4}:',
-                                              _context.ip_address if i == 0 
and _context.ip_address else "",
+                                              pick_default_value(default_ip, 
ringXaddr_res),
                                               valid_ucastIP,
                                               ringXaddr_res)
                 if not ringXaddr:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/crmsh-4.0.0+git.1537967262.68a0bd1e/crmsh/utils.py 
new/crmsh-4.0.0+git.1538492109.4b1170b0/crmsh/utils.py
--- old/crmsh-4.0.0+git.1537967262.68a0bd1e/crmsh/utils.py      2018-09-26 
15:07:42.000000000 +0200
+++ new/crmsh-4.0.0+git.1538492109.4b1170b0/crmsh/utils.py      2018-10-02 
16:55:09.000000000 +0200
@@ -110,12 +110,14 @@
         if info[0] is None and len(sp) >= 5 and sp[0] == 'default' and sp[1] 
== 'via':
             info[0] = sp[4]
         if info[0] is not None and valfor(sp, 'dev') == info[0] and sp[0] != 
'default':
+            src = valfor(sp, 'src')
             if sp[0].find('/') >= 0:
                 nw, length = sp[0].split('/')
-                info[1], info[2], info[3] = valfor(sp, 'src'), nw, length
+                info[1], info[2], info[3] = src, nw, length
+                break
             # we are reading /32 route entry
             else:
-                info[1], info[2], info[3] = valfor(sp, 'src'), sp[0], 32
+                info[1], info[2], info[3] = src, sp[0], 32
     if info[0] is None:
         raise ValueError("Failed to determine default network interface")
     return tuple(info)
@@ -153,6 +155,13 @@
 
 
 def ip_in_local(IPv6=False):
+    # short-circuit ip list handling for
+    # cloud providers in order to use
+    # metadata service instead
+    ips = iplist_for_cloud()
+    if len(ips) > 0:
+        return ips
+
     if not IPv6:
         regex = r' [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]+ '
     else:
@@ -2056,5 +2065,94 @@
     def version(self):
         return self.addr.version
 
+# Set by detect_cloud() or iplist_for_cloud()
+# to avoid multiple requests
+_ip_for_cloud = None
+
+
+def _cloud_metadata_request(uri, headers={}):
+    try:
+        import urllib2 as urllib
+    except ImportError:
+        import urllib.request as urllib
+    req = urllib.Request(uri)
+    for header, value in headers.items():
+        req.add_header(header, value)
+    try:
+        resp = urllib.urlopen(req, timeout=5)
+        content = resp.read()
+        if type(content) != str:
+            return content.decode('utf-8').strip()
+        return content.strip()
+    except urllib.URLError:
+        return None
+
+
+@memoize
+def detect_cloud():
+    """
+    Tries to determine which (if any) cloud environment
+    the cluster is running on.
+
+    This is mainly done using dmidecode.
+
+    If the host cannot be determined, this function
+    returns None. Otherwise, it returns a string
+    identifying the platform.
+
+    These are the currently known platforms:
+
+    * amazon-web-services
+    * microsoft-azure
+    * google-cloud-platform
+
+    """
+    global _ip_for_cloud
+
+    if not is_program("dmidecode"):
+        return None
+    rc, system_version = get_stdout("dmidecode -s system-version")
+    if re.search(r"\<.*\.amazon\>", system_version) is not None:
+        return "amazon-web-services"
+    if rc != 0:
+        return None
+    rc, system_manufacturer = get_stdout("dmidecode -s system-manufacturer")
+    if rc == 0 and "microsoft corporation" in system_manufacturer.lower():
+        # To detect azure we also need to make an API request
+        result = _cloud_metadata_request(
+            
"http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2017-08-01&format=text";,
+            headers={"Metadata": "true"})
+        if result:
+            _ip_for_cloud = result
+            return "microsoft-azure"
+    rc, bios_vendor = get_stdout("dmidecode -s bios-vendor")
+    if rc == 0 and "Google" in bios_vendor:
+        # To detect GCP we also need to make an API request
+        result = _cloud_metadata_request(
+            
"http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip";,
+            headers={"Metadata-Flavor": "Google"})
+        if result:
+            _ip_for_cloud = result
+            return "google-cloud-platform"
+    return None
+
+
+def iplist_for_cloud():
+    """
+    Return list of viable IPs for the
+    current cloud provider (if any)
+    """
+    global _ip_for_cloud
+    provider = detect_cloud()
+    if _ip_for_cloud is not None:
+        return [_ip_for_cloud]
+    if provider == "amazon-web-services":
+        uri = "http://169.254.169.254/latest/meta-data/local-ipv4";
+        result = _cloud_metadata_request(uri)
+        if result:
+            _ip_for_cloud = result
+            return [_ip_for_cloud]
+    return []
+
 
 # vim:ts=4:sw=4:et:


Reply via email to