Skip to content

Commit

Permalink
ENT-3276: Merge syspurpose with subscription-manager (#2436)
Browse files Browse the repository at this point in the history
* There is now syspurpose CLI tool anymore
* All functionality of syspurpose CLI is part of
  subscription-manager
* Moved few files from ./syspurpose/src/syspurpose package
  to ./src/syspurpose (files and utils modules)
* Moved some syspurpose unit tests to subscription-manager
  unit tests directory
* Fixed Makefile and .spec file. The syspurpose RPM is not
  build anymore
* Fixed .spec file to mark several directories as part of
  subscription-manager RPM
* Deleted most of .po files. Most of translation was related
  to syspurpose CLI
* Updated REDAME.md a little
* Fixed several unit tests
  • Loading branch information
jirihnidek authored Feb 22, 2021
1 parent 5ec6be6 commit ea8c1f5
Show file tree
Hide file tree
Showing 39 changed files with 73 additions and 4,242 deletions.
29 changes: 3 additions & 26 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ INITIAL_SETUP_INST_DIR := $(ANACONDA_ADDON_INST_DIR)/$(ANACONDA_ADDON_NAME)
POLKIT_ACTIONS_INST_DIR := $(INSTALL_DIR)/polkit-1/actions
COMPLETION_DIR ?= $(INSTALL_DIR)/bash-completion/completions/
LIBEXEC_DIR ?= $(shell rpm --eval='%_libexecdir')
SUBPACKAGES ?= $(shell ls -d syspurpose)

# If we skip install ostree plugin, unset by default
# override from spec file for rhel6
Expand Down Expand Up @@ -95,7 +94,6 @@ INSTALL_DNF_PLUGINS ?= false
DNF_PLUGINS_SRC_DIR := src/plugins

INSTALL_ZYPPER_PLUGINS ?= false
INCLUDE_SYSPURPOSE ?= 0

# sets a version that is more or less latest tag plus commit sha
VERSION ?= $(shell git describe | awk ' { sub(/subscription-manager-/,"")};1' )
Expand All @@ -122,23 +120,14 @@ STYLEFILES=$(PYFILES) $(BIN_FILES)

.DEFAULT_GOAL := build

build-subpackages:
for subpackage in $(SUBPACKAGES); \
do \
pushd $$subpackage; \
$(PYTHON) ./setup.py clean --all; \
$(PYTHON) ./setup.py build; \
popd; \
done;

# Install doesn't perform a build if it doesn't have too. Best to clean out
# any cruft so developers don't end up install old builds.
ifeq ($(WITH_SUBMAN_GUI),true)
build: rhsmcertd rhsm-icon build-subpackages
build: rhsmcertd rhsm-icon
EXCLUDE_PACKAGES:="$(EXCLUDE_PACKAGES)" $(PYTHON) ./setup.py clean --all
EXCLUDE_PACKAGES:="$(EXCLUDE_PACKAGES)" $(PYTHON) ./setup.py build --quiet --gtk-version=$(GTK_VERSION) --rpm-version=$(VERSION)
else
build: rhsmcertd build-subpackages
build: rhsmcertd
EXCLUDE_PACKAGES:="$(EXCLUDE_PACKAGES)" $(PYTHON) ./setup.py clean --all
EXCLUDE_PACKAGES:="$(EXCLUDE_PACKAGES)" $(PYTHON) ./setup.py build --quiet --gtk-version=$(GTK_VERSION) --rpm-version=$(VERSION)
endif
Expand Down Expand Up @@ -205,10 +194,7 @@ install-conf:
install -d $(DESTDIR)/$(POLKIT_ACTIONS_INST_DIR)
install -m 644 etc-conf/dbus/polkit/com.redhat.RHSM1.policy $(DESTDIR)/$(POLKIT_ACTIONS_INST_DIR)
install -m 644 etc-conf/dbus/polkit/com.redhat.RHSM1.Facts.policy $(DESTDIR)/$(POLKIT_ACTIONS_INST_DIR)
if [[ "$(INCLUDE_SYSPURPOSE)" = "1" ]]; then \
install -m 644 etc-conf/syspurpose/valid_fields.json $(DESTDIR)/etc/rhsm/syspurpose/valid_fields.json; \
install -m 644 etc-conf/syspurpose.completion.sh $(DESTDIR)/$(COMPLETION_DIR)/syspurpose; \
fi;
install -m 644 etc-conf/syspurpose/valid_fields.json $(DESTDIR)/etc/rhsm/syspurpose/valid_fields.json; \
if [[ "$(WITH_SUBMAN_GUI)" == "true" ]]; then \
install -m 644 etc-conf/dbus/polkit/com.redhat.SubscriptionManager.policy $(DESTDIR)/$(POLKIT_ACTIONS_INST_DIR); \
install -m 644 etc-conf/subscription-manager-gui.appdata.xml $(DESTDIR)/$(INSTALL_DIR)/appdata/subscription-manager-gui.appdata.xml; \
Expand Down Expand Up @@ -348,9 +334,6 @@ install-via-setup: install-subpackages-via-setup
else \
rm $(DESTDIR)/$(PREFIX)/bin/rhn-migrate-classic-to-rhsm; \
fi;
if [[ "$(INCLUDE_SYSPURPOSE)" = "1" ]]; then \
mv $(DESTDIR)/$(PREFIX)/bin/syspurpose $(DESTDIR)/$(PREFIX)/sbin/; \
fi;
find $(DESTDIR)/$(PYTHON_SITELIB) -name requires.txt -exec sed -i '/dbus-python/d' {} \;


Expand Down Expand Up @@ -441,16 +424,10 @@ gettext:
# the string marked for translation beginning with "translators" will be
# included in the pot file.
$(PYTHON) ./setup.py gettext
pushd ./syspurpose; \
${PYTHON} ./setup.py gettext; \
popd

.PHONY: update-po
update-po:
$(PYTHON) ./setup.py update_trans
pushd ./syspurpose; \
$(PYTHON) ./setup.py update_trans; \
popd

.PHONY: uniq-po
uniq-po:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Due to unintuitive behavior with `sys.path`
as expected. One can run the script like this instead:

```bash
PYTHONPATH=./src:./syspurpose/src python -m subscription_manager.scripts.subscription_manager
PYTHONPATH=./src python -m subscription_manager.scripts.subscription_manager
```

Similar for other bin scripts:
Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@
'*.ga_impls',
'*.ga_impls.*',
'*.plugin.ostree',
'*.services.examples',
'syspurpose*'
'*.services.examples'
]
)

Expand Down
2 changes: 1 addition & 1 deletion src/subscription_manager/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from rhsm import ourjson as json
from subscription_manager.isodate import parse_date
from subscription_manager.utils import get_supported_resources
from subscription_manager.syspurposelib import post_process_received_data
from syspurpose.files import post_process_received_data

from rhsmlib.services import config, syspurpose

Expand Down
36 changes: 9 additions & 27 deletions src/subscription_manager/managercli.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
from rhsm.connection import ProxyException, UnauthorizedException, ConnectionException, RemoteServerException
from rhsm.utils import remove_scheme, ServerUrlParseError

from syspurpose.files import SyncedStore, post_process_received_data

from subscription_manager import identity
from subscription_manager.branding import get_branding
from subscription_manager.entcertlib import EntCertActionInvoker, CONTENT_ACCESS_CERT_CAPABILITY
Expand All @@ -67,7 +69,7 @@
none_wrap_columnize_callback, echo_columnize_callback, highlight_by_filter_string_columnize_cb
from subscription_manager.utils import generate_correlation_id
from subscription_manager.syspurposelib import save_sla_to_syspurpose_metadata, \
get_syspurpose_valid_fields, post_process_received_data
get_syspurpose_valid_fields
from subscription_manager.packageprofilelib import PackageProfileActionInvoker

from subscription_manager.i18n import ungettext, ugettext as _
Expand Down Expand Up @@ -624,13 +626,6 @@ def __init__(self, name, shortdesc=None, primary=False, attr=None, commands=('se
help=_("list all {attr} available").format(attr=attr)
)

def _get_synced_store(self):
try:
from syspurpose.files import SyncedStore
return SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)
except ImportError:
return None

def _validate_options(self):
to_set = getattr(self.options, 'set', None)
to_unset = getattr(self.options, 'unset', None)
Expand Down Expand Up @@ -902,7 +897,7 @@ def _do_command(self):
except Exception as err:
log.debug("Error: Unable to retrieve %s from server: %s" % (self.attr, err))

self.store = self._get_synced_store()
self.store = SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)

if getattr(self.options, 'unset', None):
self.unset()
Expand Down Expand Up @@ -1052,18 +1047,6 @@ def __init__(self):
help=_("show current system purpose")
)

def _get_synced_store(self):
"""
Try to get SyncedStore.
TODO: refactor (remove) this, when AbstractSyspurposeCommand is merged to SyspurposeCommand
:return: Instance of SyncedStore or None
"""
try:
from syspurpose.files import SyncedStore
return SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)
except ImportError:
return None

def _validate_options(self):
"""
Validate provided options
Expand Down Expand Up @@ -1091,10 +1074,9 @@ def _do_command(self):
except Exception as err:
log.debug("Error: Unable to retrieve system purpose from server: %s" % err)
else:
self.store = self._get_synced_store()
if self.store is not None:
sync_result = self.store.sync()
content = sync_result.result
self.store = SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)
sync_result = self.store.sync()
content = sync_result.result
else:
content = syspurposelib.read_syspurpose()
print(json.dumps(content, indent=2, ensure_ascii=False, sort_keys=True))
Expand Down Expand Up @@ -1462,15 +1444,15 @@ def _do_command(self):

def set(self):
if self.cp.has_capability("syspurpose"):
self.store = self._get_synced_store()
self.store = SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)
super(ServiceLevelCommand, self).set()
else:
self.update_service_level(self.options.set)
print(_("Service level set to: \"{val}\".").format(val=self.options.set))

def unset(self):
if self.cp.has_capability("syspurpose"):
self.store = self._get_synced_store()
self.store = SyncedStore(uep=self.cp, consumer_uuid=self.identity.uuid)
super(ServiceLevelCommand, self).unset()
else:
self.update_service_level("")
Expand Down
13 changes: 2 additions & 11 deletions src/subscription_manager/syspurposelib.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,13 @@
from rhsm.connection import ConnectionException
from subscription_manager import certlib
from subscription_manager import injection as inj
from syspurpose.files import SyncedStore, USER_SYSPURPOSE, CACHED_SYSPURPOSE

import logging
import json
import os
log = logging.getLogger(__name__)

try:
from syspurpose.files import SyncedStore, USER_SYSPURPOSE, post_process_received_data, CACHED_SYSPURPOSE
except ImportError:
log.debug("Could not import from module syspurpose.")
SyncedStore = None
USER_SYSPURPOSE = "/etc/rhsm/syspurpose/syspurpose.json"
CACHED_SYSPURPOSE = "/var/lib/rhsm/cache/syspurpose.json"

def post_process_received_data(data):
return data
log = logging.getLogger(__name__)

store = None
syspurpose = None
Expand Down
File renamed without changes.
15 changes: 7 additions & 8 deletions syspurpose/src/syspurpose/files.py → src/syspurpose/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
import os
import errno
import io
from syspurpose.utils import system_exit, create_dir, create_file, make_utf8, write_to_file_utf8
from syspurpose.i18n import ugettext as _

from syspurpose.utils import create_dir, create_file, make_utf8, write_to_file_utf8
from subscription_manager.i18n import ugettext as _

# Constants for locations of the two system syspurpose files
USER_SYSPURPOSE_DIR = "/etc/rhsm/syspurpose"
Expand Down Expand Up @@ -101,15 +102,12 @@ def read_file(self):
except ValueError:
# Malformed JSON or empty file. Let's not error out on an empty file
if os.path.getsize(self.path):
system_exit(
os.EX_CONFIG,
_("Error: Malformed data in file {}; please review and correct.").format(self.path)
)

log.error("Malformed data in file {}".format(self.path))
return False
except OSError as e:
if e.errno == errno.EACCES and not self.raise_on_error:
system_exit(os.EX_NOPERM, _('Cannot read syspurpose file {}\nAre you root?').format(self.path))
log.error('Cannot read syspurpose file {}\n'.format(self.path))
return False
if e.errno == errno.ENOENT and not self.raise_on_error:
log.error('Unable to read file {file}: {error}'.format(file=self.path, error=e))
return False
Expand Down Expand Up @@ -459,6 +457,7 @@ def _check_key_value_validity(self, key, value):
:param value: provided value
:return: None
"""
# FIXME: it is not good idea to print something in this package
if self.valid_fields is not None:
if key in self.valid_fields:
if value not in self.valid_fields[key]:
Expand Down
37 changes: 5 additions & 32 deletions syspurpose/src/syspurpose/utils.py → src/syspurpose/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,10 @@
import json
import os
import errno
import sys
import logging
import six
from syspurpose.i18n import ugettext as _

HOST_CONFIG_DIR = "/etc/rhsm-host/" # symlink inside docker containers


# Borrowed from the subscription-manager cli script
def system_exit(code, msgs=None):
"""Exit with a code and optional message(s). Saved a few lines of code."""

if msgs:
if type(msgs) not in [type([]), type(())]:
msgs = (msgs, )
for msg in msgs:
sys.stderr.write(str(msg) + '\n')
sys.exit(code)
log = logging.getLogger(__name__)


def create_dir(path):
Expand All @@ -55,8 +42,7 @@ def create_dir(path):
# If the directory exists no changes necessary
return False
if e.errno == errno.EACCES:
system_exit(os.EX_NOPERM,
_('Cannot create directory {}\nAre you root?').format(path))
log.error('Cannot create directory {}'.format(path))
return True


Expand All @@ -77,25 +63,12 @@ def create_file(path, contents):
# If the file exists no changes necessary
return False
if e.errno == errno.EACCES:
system_exit(os.EX_NOPERM, _("Cannot create file {}\nAre you root?").format(path))
log.error("Cannot create file {}".format(path))
else:
raise
return True


# Borrowed from the subscription-manager config module
def in_container():
"""
Are we running in a docker container or not?
Assumes that if we see host rhsm configuration shared with us, we must
be running in a container.
"""
if os.path.exists(HOST_CONFIG_DIR):
return True
return False


def make_utf8(obj):
"""
Transforms the provided string into unicode if it is not already
Expand All @@ -105,7 +78,7 @@ def make_utf8(obj):
if six.PY3:
return obj
elif obj is not None and isinstance(obj, str) and not isinstance(obj, unicode):
obj = obj.decode('utf-8')
obj = obj.decode('utf-8')
return obj
else:
return obj
Expand Down
Loading

0 comments on commit ea8c1f5

Please sign in to comment.